So I have this code that someone had posted from awhile back. It has been working flawlessly for a year now. It takes the google form answers and posts them to discord channel as a webhook. Now since yesterday, it is not working anymore. Nothing has changed with the script.
function onSubmit(e) {
var form = FormApp.getActiveForm();
var POST_URL = "****";
var allResponses = form.getResponses();
var latestResponse = allResponses[allResponses.length - 1];
var response = latestResponse.getItemResponses();
var items = [];
for (var i = 0; i < response.length; i++) {
var question = response[i].getItem().getTitle();
var answer = response[i].getResponse();
try {
var parts = answer.match(/[\s\S]{1,1024}/g) || [];
} catch (e) {
var parts = answer;
}
if (answer == "") {
continue;
}
for (var j = 0; j < parts.length; j++) {
if (j == 0) {
items.push({
"name": question,
"value": parts[j],
"inline": false
});
} else {
items.push({
"name": question.concat(" (cont.)"),
"value": parts[j],
"inline": false
});
}
}
}
var options = {
"method":"POST",
"payload": JSON.stringify({
"content":"Hello, World!",
"embeds":[{
"title":"War Times Form",
"fields":items,
"footer":{
"text":"***Please verify these are Correct***"
}
}]
})
};
Logger.log("[METHOD] onFormSubmit");
Logger.log(items);
Logger.log(options);
var response = UrlFetchApp.fetch(POST_URL, options);
Logger.log(response);
};
This is what logging is saying its submitting
[19-11-24 10:13:28:400 PST] {method=POST, payload={"content":"Hello, World!","embeds":[{"title":"War Times Form","fields":[{"name":"Post your clan name:","value":"fds","inline":false},{"name":"Post your name","value":"fds","inline":false},{"name":"Clan that you are declaring against:","value":"dfsa","inline":false},{"name":"Days and times your group is available was HQ fight (must be in EST):","value":"sdaf","inline":false}],"footer":{"text":"***Please verify these are Correct***"}}]}}
However, I keep getting this error:
Request failed for https://discordapp.com returned code 400. Truncated server response: {"message": "Cannot send an empty message", "code": 50006} (use muteHttpExceptions option to examine full response)
at onSubmit(Code:54)
Any help that anyone can give me would be great. I have tried contacting discord support and they wont help as its API/Dev
So found the answer had to add to the options that get sent through the request. Discord apparently changed it and didn't tell anyone that you have to declare it
"contentType" : "application/json",
Related
I need to verify whether a particular node in the response body of an API is null or a string. How is it done using ChaiJS in postman tests?
Sample API response body:
[
{
"exercise_num": "1",
"expire_date": "2019-03-11T16:31:17.935Z",
"created_at": "2019-03-15T11:44:35.698Z"
},
{
"exercise_num": "2",
"expire_date": null,
"created_at": "2019-03-15T11:44:38.363Z"
}
]
I would like to verify that the expire_date node in the above sample API response body will either only contain null or a string data type and it won't return any other data type such as int, etc.
I have tried the following:
var jsonData = JSON.parse(responseBody);
pm.test('All expire_date contains either string or null', () => {
for (i = 0; i < jsonData.length; i++) {
if(jsonData[i].expire_date === null){
tests["expire_date is null"] = true;
}
else{
pm.expect(jsonData[i].expire_date).to.be.a('string');
}
}
});
The test passes.
I'm expecting if something like this can be done:
pm.test('All expire_date contains string', () => {
for (i = 0; i < jsonData.length; i++) {
pm.expect(jsonData[i].expire_date).to.be.a('string' || null);
}
});
I believe there is no direct way with || operator though, you can check with data types. As null is an object type in javaScript, write the test case as follows:
var jsonData = JSON.parse(responseBody);
pm.test('All expire_date contains string', () => {
for (i = 0; i < jsonData.length; i++) {
pm.expect(typeof jsonData[i].expire_date).to.be.oneOf(['string', 'object']);
}
});
That's probably an easy way, and can be used in simple checks. However, I'd recommend you to use the second way, i.e. using The fastest JSON Schema Validator.
var Ajv = require('ajv'),
ajv = new Ajv({logger: console}),
schema = {
"properties": {
"expireDate": {
"type": ["string","null"]
}
}
};
var jsonData = JSON.parse(responseBody);
pm.test('All expire_date contains string', function() {
for (i = 0; i < jsonData.length; i++) {
pm.expect(ajv.validate(schema, {expireDate: jsonData[i].expire_date})).to.be.true;
}
});
If you'd like you check this in multiple requests, put schema at collection level.
I have this code, the thing with it is, I need it to get some data from that website, the string in apiurl. This code needs to download these websites, with the certain appids found in the json. It needs to download the data on these websites and store them in a json file. For some reason this does not work.
I have this piece of code in a .js file:
var gamekeys = JSON.parse(fs.readFileSync('gamekeys.json'));
var jsonstring = JSON.stringify(gamekeys, null, 4);
UpdateGamePricelist();
function UpdateGamePricelist() {
for(var i = 0;i<gamekeys.keys.length;i++) {
appid = gamekeys.keys[i].appid;
var apiurl = "http://store.steampowered.com/api/appdetails?appids="+appid;
if (i < 95) {
request(apiurl, function(err, response, body) {
if (err) {
console.log("Error when updating game prices: " + err+"\n");
return;
}
var apiresponse = JSON.parse(body);
if (body == "") {
console.log("Could not find a pricelist m8");
return;
}
fs.writeFile("C:/Users/ahmad/Desktop/Bots/SteamKeyProfitter/gamespricelist/"+appid+".json", body, function(err) {
if(err) {
console.log("Error saving data to game pricelist: " + err);
return;
}
console.log("Game pricelist has been updated!");
});
});
}
}
}
And I have a json file, the json file called gamekeys.json
Here it is:
{
"keys": [
{
"appid": 10,
"price":0,
"listofkeys":[],
"game": "Counter-Strike"
},
{
"appid": 20,
"price":0,
"listofkeys":[],
"game": "Team Fortress Classic"
},
{
"appid": 30,
"price":0,
"listofkeys":[],
"game": "Day of Defeat"
},
{
"appid": 40,
"price":0,
"listofkeys":[],
"game": "Deathmatch Classic"
},
It ofcourse keeps going (2 million lines of that)
Why does the first code not create 95 json files?
The problems is that your appid is the same for all of the writeFile invocations.
Try changing:
appid = gamekeys.keys[i].appid;
to:
let appid = gamekeys.keys[i].appid;
You need a fresh binding for all of the callbacks or otherwise they all get the same value (from the last loop iteration). Note that var would not work here, you need let. If you use i in one of the closures then you also need to use for (let i = ...) instead of for (var i = ...)
apiurl can be declared with var because its value is passed to the request() invocation instead of being captured by a closure, but if you use let alle of the time and never use var you wouldn't have to worry about it.
If you always start every program with 'use strict'; (with quotes) and never use var (using let or const instead) then you will not have problems with the scoping that you have here, so it's a good practice to follow and enforce with linters.
This is one of the problems. There may be more but this is certainly one of them.
Update
Answering the comment by Alex "why can't he use var appid"
Run this code:
for (var i = 0; i < 4; i++) {
let appid = 'ID' + i;
setTimeout(function () {
console.log(appid);
}, 500 * i);
}
And run this program:
for (var i = 0; i < 4; i++) {
var appid = 'ID' + i;
setTimeout(function () {
console.log(appid);
}, 500 * i);
}
And compare the output.
This demonstrates the difference between let and var.
See this answer for more info about the difference between let and var:
Why let and var bindings behave differently using setTimeout function?
I'm working on a personal project and I'm stump in the last part. I'm trying to only get the data for companies that have the same name of the companies in my database.
My goal at the end is to merge the two jsons obtained from the two following calls into one
Call one: $http.get('//localhost:8081/api/jobs').then(function(res)
Call two: localhost:8081/api/glassdoor/
Full Code:
$http.get('//localhost:8081/api/jobs').then(function(res) {
$scope.data = res.data; //data from the database
$scope.size = $scope.data.length; //length 132
for (var i = 0; i < $scope.size; i++) {
if ($scope.data[i].glassdoor !== null && $scope.data[i].glassdoor !== undefined) {
$scope.hasGlassdoor = [];
for (var i = 0; i < $scope.size; i++) {
if ($scope.data[i].glassdoor !== null && $scope.data[i].glassdoor !== undefined)
$scope.hasGlassdoor.push($scope.data[i]);
}
//Get the companies name that have glassdoor
$scope.company = [];
for (var j = 0; j < $scope.hasGlassdoor.length; j++) {
$scope.company.push($scope.hasGlassdoor[j].company);
}
//Create the URL calls for my glassdoor api
$scope.url = [];
for (var x = 0; x < $scope.company.length; x++) {
$scope.url.push('//localhost:8081/api/glassdoor/' + $scope.company[x]);
}
//For example : '//localhost:8081/api/glassdoor/A9.com'
//Get the Glassdoor data
var company = $scope.company;
for (var j = 0; j < $scope.url.length; j++) {
$http.get($scope.url[j]).then(function(response) {
$scope.gData = response.data;
$scope.gSize = $scope.gData.length;
$scope.gName = [];
//Get the names of the companies that glassdoor returns
for(var x = 0; x < $scope.gSize; x++){
if ($scope.gData[x] !== null && $scope.gData[x] !== undefined) {
if ($scope.gData[x].name !== null && $scope.gData[x].name !== undefined) {
$scope.gName.push($scope.gData[x].name);
}
}
}
//Now I'm trying to only get the names of the companies that are in my variable company
//For example '//localhost:8081/api/glassdoor/6sense
//returns data for 6sense, and a company named 6sense Technologies
//I'm trying to just get the data of 6sense
//
// TODO
//
// My try using loDash returns undefined.
// I'm trying to see if $scope.gName is in var Company.
//if(_.includes(company, $scope.gName)){
// gd.push($scope.gName);
//}
}); //this is what is calling the glassdoor api
}//end of the for loop for url.
} //if statement to check for null
} //first for loop
}).catch(function(error, res) {
console.log("Error:", error, res);
});
Right now I'm working on small list so I can fix this issue.
My goal at the end is to have this as my finished json:
[
{
"company": "23andMe"
"glassdoor":"https://www.glassdoor.com/Overview/Working-at-23andMe-EI_IE145899.11,18.htm"
"img":"https://www.23andme.com/static/img/icons/logo_alt.96cf7888b73d.svg"
"international":null
"link":"https://www.23andme.com/careers/"
"location":"Mountain View, CA"
"secondary":null
"third":null
"id":145899,
"name":"23andMe",
"website":"www.23andme.com",
"isEEP":true,
"exactMatch":true,
"industry":"Biotech & Pharmaceuticals",
"numberOfRatings":27,
"squareLogo":"https://media.glassdoor.com/sqll/145899/23andme-squarelogo.png",
"overallRating":"4.2",
"ratingDescription":"Very Satisfied",
"cultureAndValuesRating":"4.5",
"seniorLeadershipRating":"3.6",
"compensationAndBenefitsRating":"4.0",
"careerOpportunitiesRating":"3.4",
"workLifeBalanceRating":"4.3",
"recommendToFriendRating":80,
"sectorId":10005,
"sectorName":"Biotech & Pharmaceuticals",
"industryId":200021,
"industryName":"Biotech & Pharmaceuticals",
"featuredReview":{
"attributionURL":"https://www.glassdoor.com/Reviews/Employee-Review-23andMe-RVW11447587.htm",
"id":11447587,
"currentJob":true,
"reviewDateTime":"2016-08-03 15:05:20.157",
"jobTitle":"Customer Care Reporesentative",
"location":"Mountain View, CA",
"jobTitleFromDb":"Customer Care Reporesentative",
"headline":"Customer Care Representative",
"pros":"the environment-everyone is extremely genuine, smart, and friendly. management is very understanding and open. Executives are transparent with everything going on in the company\r\nbenefits-free gym, food every day, snacks, great health coverage, rooftop access, etc\r\nworkspace-facilities does a phenomenal job at keeping everything extremely clean and fixes all issues ASAP. I don't feel like I'm sitting a boring desk job all day, it's a fun place to be",
"cons":"Traffic through downtown mountain view can suck and the train can be kind of loud (I cannot think of a legitimate con, everything is awesome here)",
"overall":5,
"overallNumeric":5
},
"ceo":{
"name":"Anne Wojcicki",
"title":"CEO",
"numberOfRatings":15,
"pctApprove":100,
"pctDisapprove":0
}
}
]
Server.js that deals with the glassdoor call:
//Glassdoor api call
app.get('/api/glassdoor/:company', function(req, res, next) {
var company = req.params.company;
requestify.get('https://api.glassdoor.com/api/api.htm?t.p=PRODUCT&t.k=KEY&userip=0.0.0.0&useragent=&format=json&v=1&action=employers&q=' + company).then(function(response) {
// Get the response body (JSON parsed or jQuery object for XMLs)
gData = response.getBody();
gData = gData.response.employers;
res.json(gData);
});
});
Sort the array, then enumerate it. If previous === current you have a dupe.
This is how I solved it.
app.get('/api/glassdoor/:company', function(req, res, next) {
var company = req.params.company;
requestify.get('https://api.glassdoor.com/api/api.htm?t.p=PRODUCT&t.k=KEY&userip=0.0.0.0&useragent=&format=json&v=1&action=employers&q=' + company).then(function(response) {
// Get the response body (JSON parsed or jQuery object for XMLs)
gData = response.getBody();
gData = gData.response.employers;
//What I added to only send the data of the companies that where like 'company'
for (var i = 0; i < gData.length; i++) {
if (gData[i].name === company) {
gData = gData[i];
res.send(gData);
}
}
});
});
Which doesn't answer the overall question but that is how I solved my particular issue.
I am having issues searching in an array of objects. Basically what my page needs to do is to create a new "client" using information entered by me, such as Full name, User name, Email and Password. Each one of these clients are objects in an array as you can see below.
var clientlist = [{"username":"John","fullname":"John Doe",
"email":"john.doe#hotmail.com","type":"client","password":"jdoe2"},
This client is already created in my js file, what I need to do is to create a new object to add to this array with this same structure. For example,
var clientlist = [{"username":"Peter","fullname":"Peter Jones",
"email":"peter.jones#hotmail.com","type":"client","password":"pjones1"},
I have written the code but it doesn't work properly, when I run the Firebug I can see that all elements have been added correctly except for the Username which value is "". I cannot seem to search for the username to see if the username that I am adding already exists, it may be a syntax mistake. I will leave my complete code below and thanks in advance for the assistance!.
var clientlist = [{"username":"John","fullname":"John Doe",
"email":"john.doe#hotmail.com","type":"client","password":"jdoe2"},
var Client = {};
function NewClient(){
var found;
var user = $("#username").val();
for (var i = 0; i < clientlist.length; i++) {
if (clientlist[i].username == user) {
found = true;
}else{
found = false;
}
}
if (found == true){
$("#msj").html("User already exists!");
}
else if(found == false){
Client["fullname"] = $("#fullname").val();
Client["username"] = user;
Client["email"] = $("#email").val();
Client["type"] = "client";
Client["password"] = $("#password").val();
clientlist[clientlist.length] = Client;
$("#msj").html("New client has been created");
}
}
Few mistakes that you made:
Forgot to close the clientlist array
Forgot to actually push the newly added client
This code below should work correcting a few mistakes that you made along the way.
var clientlist = [{
"username": "John",
"fullname": "John Doe",
"email": "john.doe#hotmail.com",
"type": "client",
"password": "jdoe2"
}];
function NewClient() {
var found = false;
var user = $("#username").val();
for (var i = 0; i < clientlist.length; i++) {
if (clientlist[i].username == user) {
found = true;
} else {
found = false;
}
}
if (found) {
$("#msj").html("User already exists!");
} else {
var newUser = {
fullname: $("#fullname").val(),
username: user,
email: $("#email").val(),
type: "client",
password: $("#password").val()
}
clientlist.push(newUser);
$("#msj").html("New client has been created");
}
}
Made a fiddle for you:
http://codepen.io/gabrielgodoy/pen/xOxoWw?editors=1011
I guess, you have several issues.
Ending bracket of the clientList
For loop and the found variable
pushing new user to the client list.
I have corrected them and included it below.
<script>
var clientlist = [{"username":"John","fullname":"John Doe",
"email":"john.doe#hotmail.com","type":"client","password":"jdoe2"}]
function NewClient(){
var found=false;
var user = $("#username").val();
for (var i = 0; i < clientlist.length; i++) {
if (clientlist[i].username==user) {
found = true;
break;
}
}
if (found){
$("#msj").html("User already exists!");
}
else{
var newUser={
fullname:$("#fullname").val(),
username:user,
email:$("#email").val(),
type:"client",
password:$("#password").val()
}
clientlist.push(newUser);
$("#msj").html("New client has been created");
}
}
</script>
I am writing a script on parse.com's javascript cloud code SDK. Here is the information I have saved in my parse.com account and what I am trying to do with it.
I have a bunch of items saved in a parse class called TestItem, theses items have an objectId, item name, meal time (lunch, dinner) and a location for there columns. I also have a class called UserFavourites. In this class the objects have an objectId, item name and a pointer to the user who saved the item as a favourite.
And with this information I am trying to write a cloud code script in javascript. That will match the an item(s) to the item(s) that a user has favourited and send them a push notification saying where and what the item is and the location of the item. I have some code that will do that but this code will send a different notification for each item which could get annoying for the user here is that code.
Parse.Cloud.define("push", function(request, response) {
var TestItem = Parse.Object.extend("TestItem");
var query = new Parse.Query(TestItem);
query.limit(1000);
query.equalTo('school', 'Union College (NY)');
query.find({
success: function(resultsItem) {
//console.log("Successfully retrieved " + resultsItem.length + " :1111.");
for (var i = 0; i < resultsItem.length; i++) {
var object = resultsItem[i];
var item = object.get('item');
var school = object.get('school');
var meal = object.get('meal');
var meal = meal.toLowerCase();
var diningLocation = object.get('schoolMenu');
//var itemArray = [];
var UserFavourite = Parse.Object.extend("UserFavourite");
var queryFavourite = new Parse.Query(UserFavourite);
queryFavourite.limit(1000);
queryFavourite.equalTo("item", item)
queryFavourite.equalTo("school", school)
queryFavourite.find({
success: function(results) {
for (var i = 0; i < results.length; i++) {
var objectFav = results[i];
var user = objectFav.get('user');
var userID = user.id;
var realItem = objectFav.get('item');
console.log(objectFav.get('user'));
console.log(objectFav.get('item'));
var UserClass = Parse.Object.extend("User");
var queryUser = new Parse.Query(UserClass);
queryUser.get(userID, {
success: function(userResult) {
console.log(userResult.get('school'));
console.log('install:' + userResult.get('installation').id);
var userInstallationId = userResult.get('installation').id;
var queryInstallation = new Parse.Query(Parse.Installation);
queryInstallation.equalTo('objectId', userInstallationId);
queryInstallation.find({
success: function(results) {
console.log('number' + results.length);
Parse.Push.send({
// deviceType: [ "ios" ],
where: queryInstallation,
data: {
alert: realItem + " is being served at " + diningLocation + " for " + meal
}
},
{
success: function() {
// Push was successful
},
error: function(error) {
// Handle error
}
});
},
error: function(error) {
console.log('error');
}
});
},
error: function(error) {
console.log('error');
}
});
}
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
}
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
});
As you can see it is quite long and not very nice looking, I tried to save items to an array so to avoid sending two or more notifications but couldn't get that to work.
So I started writing another script that uses promises which looks much nicer but haven't gotten it all the way right now, it can match the items to users that have an item favourited and put the objectId's of those users in an array. Here is that code.
Parse.Cloud.define("test", function(request, response) {
var UserFavourite = Parse.Object.extend("UserFavourite");
var queryFavourite = new Parse.Query(UserFavourite);
var userArray = [];
var TestItem = Parse.Object.extend("TestItem");
var query = new Parse.Query(TestItem);
query.limit(1000);
query.equalTo('school', 'Union College (NY)');
query.find().then(function(results) {
return results;
}).then(function(results) {
var promises = [];
for (var i = 0; i < results.length; i++) {
var object = results[i];
var item = object.get('item');
var school = object.get('school');
var meal = object.get('meal');
var UserFavourite = Parse.Object.extend("UserFavourite");
var queryUser = new Parse.Query(UserFavourite);
queryUser.equalTo("item", item);
queryUser.equalTo("school", school);
var prom = queryUser.find().then(function(users) {
for (var i = 0; i < users.length; i++) {
var user = users[i];
var userID = user.get('user').id;
if (userArray.indexOf(userID) === -1) {
userArray.push(userID);
}
}
return userArray;
});
promises.push(prom);
}
return Parse.Promise.when.apply(Parse.Promise, promises);
}).then(function(results) {
console.log(userArray);
});
});
But now with this code I don't know where to go, I think using promises and such is the right way to go but I am now confused as once I have all the users that have an item favourited what to do, I then need to get there items that are favourited and are available in the TestItem class, this is where I am struggling.
Here is a pic of my UserFavourite class it has a pointer to the user who favorited the item as you can see, and also a user has more than one favorite.
Thanks a bunch for the help in advance.
Here is your code, and I changed a couple things.
Parse.Cloud.define("getAllFavoriteItems", function (request, response) {
var TestItems = Parse.Object.extend("TestItems");
var UserFavorites = Parse.Object.extend("UserFavorites");
var testItemsQuery = new Parse.Query(TestItems);
var userFavoritesQuery = new Parse.Query(UserFavorites);
testItemsQuery.equalTo('school', 'Union College (NY)');
userFavoritesQuery.include('testItems'); //This makes sure to pull all of the favorite item data instead of just the pointer object
userFavoritesQuery.matchesQuery('testItem', testItemsQuery); //This will run this second query against the TestItems
userFavoritesQuery.limit(1000); //limit results to 1000
userFavoritesQuery.ascending('userId'); //group the user id's together in your array
userFavoritesQuery.find({
success:function(results) {
var pushNotificationMessage = "";
var userId = "";
for (var i=0; i <results.length; i++) {
if (results[i].get('userId') != userId) {
if (results[i].get('userId') != "") {
//TODO send push notification
}
userId = results[i].get('userId');
pushNotificationMessage = ""; //start a new push notification
}
pushNotificationMessage += results[i].get('item').get('name') + ": " + results[i].get('item').get('location') + "\n";
//SOMEWHERE BEFORE HERE I NEED THE INSTALLATION ID OF THE USER
//TO SEND THE PUSH TO THAT USER
Parse.Push.send({
// deviceType: [ "ios" ],
where: queryInstallation,
data: {
alert: pushNotificationMessage
}
},
{
success: function() {
// Push was successful
},
error: function(error) {
// Handle error
}
});
}
response.success(true);
},
error:function(error) {
response.error();
}
})
});
Some code that might create push per user, rough outline though
if (i > 0) {
if (results[i].get('user') === results[i-1].get('user')) {
userItems.push(results[i]);
}
else {
userItems.length = 0;
}
}
else {
userItems.push(results[i]);
}
Not sure let me know if you understand what I'm trying to do...
So it a user has two items favourited I want it to group that into one, phrase that says what and where both items are being served
And here is code to send push
Parse.Push.send({
// deviceType: [ "ios" ],
where: queryInstallation,
data: {
alert: pushNotificationMessage
}
},
{
success: function() {
// Push was successful
},
error: function(error) {
// Handle error
}
});
It can also be done with then/ promises,
I agree with #Maxwell that your UserFavorite should have links to both User and TestItem. This makes it possible to make your cloud-function as simple as:
Parse.Cloud.define("getAllFavoriteItems", function(request, response) {
var TestItem = Parse.Object.extend("TestItem");
var UserFavorites = Parse.Object.extend("UserFavorites");
var testItemsQuery = new Parse.Query(TestItem);
var userFavoritesQuery = new Parse.Query(UserFavorites);
testItemsQuery.equalTo('school', request.params.school);
userFavoritesQuery.include('testItem');
userFavoritesQuery.include('user');
userFavoritesQuery.matchesQuery('testItem', testItemsQuery); //This will run this second query against the TestItems
userFavoritesQuery.find().then(function(results) {
var alerts = {};
for(var i =0 ; i<results.length; i++ ){
var user = results[i].get('user');
var testItem = results[i].get('testItem');
if(user && testItem){
var instId = user.get('installationId');
if(!alerts[instId]) {
alerts[instId] = [];
}
var m = results[i].get('item') + " is being served at {{diningLocation}} for " + testItem.get('meal');
alerts[instId].push(m);
}
}
response.success(alerts);
}, function(error) {
response.error();
});
});
This is working code that you can also find in my github repo.
You can also see the working demo here
The idea is the same as in Maxwell's answer: to have link in UserFavorites class to both User (where installationId is located) and TestItem entities. I've just made it working by including user and testItems properties in query, so when the result is returned filtered by school name I already have a list of installationIds.
Here is my schema:
User
TestItem
UserFavorites
Update:
In this code I added push notifications:
Parse.Cloud.define("getAllFavoriteItems", function(request, response) {
var TestItem = Parse.Object.extend("TestItem");
var UserFavorites = Parse.Object.extend("UserFavorites");
var testItemsQuery = new Parse.Query(TestItem);
var userFavoritesQuery = new Parse.Query(UserFavorites);
testItemsQuery.equalTo('school', request.params.school);
function SendPush(installationId, msg) {
var query = new Parse.Query(Parse.Installation);
query.equalTo('objectId', installationId);
Parse.Push.send({
where: query,
data: {alert: msg}
});
}
userFavoritesQuery.include('testItem');
userFavoritesQuery.include('user');
userFavoritesQuery.matchesQuery('testItem', testItemsQuery); //This will run this second query against the TestItems
userFavoritesQuery.find().then(function(results) {
var groupedAlerts = {};
// manually iterating though results to get alert strings ang group by user in groupedAlerts[installationId]
for(var i =0 ; i<results.length; i++ ){
var user = results[i].get('user');
var testItem = results[i].get('testItem');
if(user && testItem){
var instId = user.get('installationId');
if(!groupedAlerts[instId]) {
groupedAlerts[instId] = [];
}
var m = results[i].get('item') + " is being served at {{dining Location}} for " + testItem.get('meal');
groupedAlerts[instId].push(m);
}
}
// reformat to array and send push notifications
var alerts = [];
for(var key in groupedAlerts) {
alerts.push({
installationId: key,
alerts: groupedAlerts[key],
});
// Send push notifications
SendPush(key, groupedAlerts[key].join());
}
response.success(alerts);
}, function(error) {
response.error();
});
});
I've also updated test data in live demo (just press Get Alerts) or feel free to play around with test data hot it changes cloud code response. gitnub repo is also up to up to date.
This is based on what I understand as the problem you're trying to solve. If it's not addressing the right issue, let me know and I'll see what I can do.
Looking first at your database model, we can simplify this a bit by modifying the UserFavorites table. Starting with the initial two classes, you have a table of items and a table of users. Since a user can favorite many items and an item can be favorited by many users, we have a many-to-many relationship that exists. When this happens, we need to make a third class that points to each of the other two classes. This is where the UserFavorites table comes into play. In Parse terms, the UserFavorites table needs to have two pointers in it: one for the user and one for the item.
Once the UserFavorite table exists with it's two pointers, we can do a few things fairly easily. In your case, we have a few searching criteria:
each item must be at a given school
you want to limit your responses to the first 1000
To accomplish this you can combine two queries into one by calling matchesQuery.
Parse.Cloud.define("getAllFavoriteItems", function (request, response) {
var TestItems = Parse.Object.extend("TestItems");
var UserFavorites = Parse.Object.extend("UserFavorites");
var testItemsQuery = new Parse.Query(TestItems);
var userQuery = new Parse.Query(Parse.User);
var userFavoritesQuery = new Parse.Query(UserFavorites);
testItemsQuery.equalTo('school', 'Union College (NY)');
userQuery.include('Installation');
userFavoritesQuery.include('testItems'); //This makes sure to pull all of the favorite item data instead of just the pointer object
userFavoritesQuery.include('User'); //This makes sure to pull all of the favorite item data instead of just the pointer object
userFavoritesQuery.matchesQuery('testItem', testItemsQuery); //This will run this second query against the TestItems
userFavoritesQuery.matchesQuery('user', userQuery); //This will run the third query against Users, bringing the installation data along with it
userFavoritesQuery.limit(1000); //limit results to 1000
userFavoritesQuery.ascending('userId'); //group the user id's together in your array
userFavoritesQuery.find({
success:function(results) {
...
},
error:function(error) {
response.error();
}
})
})
Once we get that far, then compiling the push message for each user should be a matter of straight-forward string parsing logic. For example, in the success function, one way we can extract the data we is this:
success:function(results) {
var pushNotificationMessage = "";
var userId = "";
for (var i=0; i <results.length; i++) {
if (results[i].get('userId') != userId) {
if (results[i].get('userId') != "") {
//TODO send push notification
}
userId = results[i].get('userId');
pushNotificationMessage = ""; //start a new push notification
}
pushNotificationMessage += results[i].get('item').get('name') + ": " + results[i].get('item').get('location') + "\n";
}
response.success(true);
}
I haven't tested these examples to see if they'll work, but I hope this gives you an idea of how to simplify your queries into something a little more manageable.