Parse Query equalTo not Working - parse-platform

I'm trying to simply query my database filtering results with a parameter (named: "lesson") I've just obtained from another query.
The problem is that when I try to print with an "alert" command lesson's value it says: undefined.
It is wierd that when I put "lesson" inside a tuple's field it works.
In particular line
obj.set("student", lesson);
added just for debugging purpose, actually writes a consistent value into the table.
This is the whole code:
Parse.Cloud.job("checkingTwoTables", function(request, response) {
Parse.Cloud.useMasterKey();
var stud,lesson;
//select first student of the list and check for his enters
var wholeTable = new Parse.Query("enter");
wholeTable.find({
success: function(result) {
if(result.length != 0)
{
//pick student name and lesson we're interested in
stud = result[0].get("student");
lesson = result[0].get("lesson");
}
else {}
},
error: function(error) {
console.log("failed");
}
});
alert("lesson value:" + lesson);
var selectionQuery = new Parse.Query("enter");
selectionQuery.equalTo("lesson", "cns");
selectionQuery.find({
success: function(results) {
for (var i = 0; i < results.length; i++)
{
var obj = results[i];
obj.set("raggiunto", 77);
obj.set("student", lesson); // <<-------HERE IS THE ISSUE
obj.save(null,{
success: function (object) {
response.success(object);
},
error: function (object, error) {
response.error(error);
}
});
}
},
error: function(error) {
console.log("failed");
}
}); //code continues...

You are having this exact issue.
.find() is making a request with the server. You cannot guarantee when it would finish thus you cannot guarantee that your second query will run after the first one completes. Therefore, when your second query runs, the value of lesson may still have not been retrieved yet by the first query, hence the "undefined".
The solution would be to move the second query inside the success block of the first query.

Related

Parse Cloud - Get user informations by objectId

I'm trying to get user lang from User class in Parse Cloud. lang is one of the columns in User class. I wanna get lang of the user. My entire Cloud Code is as following (it didn't work):
Parse.Cloud.beforeSave('Order', function(request, response) {
var orderState = request.object.get('orderState');
var subtitleMessage = '';
var userLang = '';
var currentUser = request.object.get('user');
var userQuery = new Parse.Query(Parse.User);
userQuery.equalTo('objectId', currentUser.id);
.find()
.then((result)=>{
userLang = result.get('lang');
})
if (orderState === undefined || ['nonApproved', 'approved', 'delivered', 'canceled'].indexOf(orderState) < 0) {
response.error("OrderState is null or not one the ['nonApproved', 'approved', 'delivered', 'canceled']!");
} else {
var query = new Parse.Query(Parse.Installation);
query.include('user');
query.equalTo('user', request.object.get('user'));
Parse.Push.send(
{
where: query,
data: {
title: "MyTitle",
alert: subtitleMessage
}
},
{
success: function() {
},
error: function(error) {
response.error(error)
},
useMasterKey: true
}
);
response.success();
}
});
The answer from Jake T. has some good points. Based on his answer and your comment on the question, you could try something like this:
Parse.Cloud.beforeSave('Order', function(request, response) {
var currentUser = request.object.get('user');
currentUser.fetch({useMasterKey: true}).then(function(user) {
var userLang = user.get('lang');
// send push notifications based on userLang here
response.success();
}).catch(function(error) {
// handle any errors here
console.error(error);
});
});
Verify you actually have a User object shell from request.object.get("user"); And, if you do, you can just call currentUser.fetch() instead of performing a query, unless there are other objects you may need to include.
Since you used a query, the result is an array, even if there is only a single object returned (or none, it would be simply []). So, you're doing Array.get("lang"), which shouldn't do anything. Try if( results && results.length > 0 ) user = results[0];, then you should be able to access user.get("lang");
You should have ACL / CLP's set up for your User class. Ideally, these should not be accessible by people who are not the user or master. So, if that is set up properly, your solution may be passing {useMasterKey:true} as an option to the query / fetch.

calling a function in Xcode

I have Inventory table in my Parse database with two relevant fields How can I do that with swift ? I create cloud code with Js below
Parse.Cloud.define("retrieveproducts", function(request, response) {
var productDictionary ={};
var query = new Parse.Query("Post");
query.each(
function(result){
var num = result.get("quantity");
if(result.get("productid") in productDictionary){
productDictionary[result.get("productid")] += num;
}
else{
productDictionary[result.get("productid")] = num;
}
}, {
success: function() {
response.success(productDictionary);
},
error: function(error) {
response.error("Query failed. Error = " + error.message);
}
});
});
I want to call this function : but i have some trouble calling it with this call
let params = ["productid": String(), "string": String()]
PFCloud.callFunctionInBackground("retrieveproducts", withParameters: params) {
(ratings, error) in
if (error == nil) {
print("\(params)")
}
}
Swift Code
let reportedId = "someUsersObjectId"
PFCloud.callFunctionInBackground("suspendUser", withParameters: ["userId": reportedId]) {
(result, error) in
if (error == nil) {
print(result)
}
}
Cloud Code:
Parse.Cloud.define("suspendUser", function(request, response) {
Parse.Cloud.useMasterKey()
//var User = Parse.Object.extend(Parse.User);
//var user = new User();
//user.id = request.params.userId;
user = new Parse.User({id:request.params.userId})
user.fetch().then(function() {
user.set("suspended", true)
user.save().then(function(newMostRecentAgain) {
response.success("Cloud code called! " + request.params.userId)
}, function(error) {
// The save failed. Error is an instance of Parse.Error.
})
});
});
So let me walk you through what's going on here, so you can better figure out how to do your code (since I can'e exactly know what you wanna do).
1: in my Swift code, withParameters is how you pass info to your cloud code, and it's in the style of a dictionary. Here I'm passing the user I wanna report's objectId.
PFCloud.callFunctionInBackground("suspendUser", withParameters: ["userId": reportedId]) {
2: In my Cloud code, I'm getting the Parse Object of the user I reported with the objectId I'm passing with the params. Since you can't pass an entire object to the cloud code, I'm rebuilding the object with the objectId and the user.Fetch() you see.
user = new Parse.User({id:request.params.userId})
3: in my Cloud code, after I successfully save my user after changing it's value for "suspended", I send a string back to the IOS user.
response.success("Cloud code called! " + request.params.userId)
4: Finally, in my Swift Code, I then print the returned string from success
print(result)
Does this make things a little bit more clear? Let me know if anything doesn't make sense.

Ajax call within a loop using $resource

I'm in difficulty doing this operation correctly.
I have an Order and for every item I have to get the data from the API, what I'm doing is this:
if ($scope.order.order_items.length > 0) {
var itemArray = [];
for (var i = 0; i < $scope.order.order_items.length; i++) {
var itemId = $scope.order.order_items[i].id;
Items.get({
itemId: itemId
}).$promise.then(function (data) {
itemArray.push(data.item);
});
}
$scope.order.order_items = itemArray;
}
The API receive the request and send the data back but the promise do not return anything...
One more error here is from jshint: Don't make functions within a loop.
It will be nice to solve both the issues for me... I tried to create an external function but having the same issue not returning data I don't know if I was doing it well, the external function I was doing is:
function addItem(id) {
Items.get({
itemId: id
}).$promise.then(function (data) {
console.log(data);
return data.item;
});
}
You are making an asynchronous call from the code and thinking that it will work like synchronously. As you are assigning itemArray to $scope.order.order_items outside the factory, at that time itemArray is blank. Before making that assignment you need to ensure that all the ajax call the each item has been completed or not. You could use $q.all for such scenario. $q.all need an promise array & it will call the .then function when all the promise gets resolved.
if ($scope.order.order_items.length > 0) {
var itemArray = [], promiseArray = [];
for (var i = 0; i < $scope.order.order_items.length; i++) {
var itemId = $scope.order.order_items[i].id;
var currentPromise = Items.get({
itemId: itemId
}).$promise.then(function (data) {
itemArray.push(data.item);
return true; //returning dummy value from promise.
});
promiseArray.push(currentPromise); //creating promise array
}
$q.all(promiseArray) //giving promise array input.
.then(function(data){ //success will call when all promises get resolved.
$scope.order.order_items = itemArray;
},function(error){
console.log("Error occured")
});
}
I would avoid reading and writing to the same array and instead use another array for the actual items.
As Resource returns an instance that gets filled on success you should be fine adding the instances to the scope directly. With that you reduce your code a lot and also remove the jshint warning.
if ($scope.order.order_items.length > 0) {
$scope.order.order_items_with_data = [];
for (var i = 0; i < $scope.order.order_items.length; i++) {
var itemId = $scope.order.order_items[i].id;
$scope.order.order_items_with_data.push(Items.get({itemId: itemId}));
}
}

parse.com A Cloud Job of few words

I am trying to create a simple Cloud Job on parse.com but it doesn't behave as expected.
The job returns without error but in the process I am making a find query that seems to be thrown out to the void. There is no error, my console.log are visible before executing query.find() but after that nothing... The query seems to fail silently.
Here is my code:
Parse.Cloud.job("maintenanceJob", function(request, status) {
return performMaintenanceTasks().then(function() {
status.success("Parse Job done");
}, function(errors) {
status.error(tools.prettifyError(errors));
});
});
function performMaintenanceTasks ()
{
// If we have more than NB_MAX_ITEMS objects in Items, let's delete some
var query = new Parse.Query(Items);
return query.count({
success: function(count) {
if(count > NB_MAX_ITEMS) {
return deleteOldItems(1); // 1 is used for test
}
return Parse.Promise.as("Nothing to do.");
},
error: function(error) {
return Parse.Promise.error(error);
}
});
}
function deleteOldItems(nbToDelete) {
// (...)
var query = new Parse.Query(Items);
query.ascending("createdAt");
query.limit(nbToDelete);
query.include("rawData");
console.log("I am visible in console, but NOTHING AFTER ME. query.find() seems to return immediately");
return query.find({
success: function (results) {
// I never pass here
var promise = Parse.Promise.as();
_.each(results, function (item) {
// For each item, extend the promise with a function to delete it.
promise = promise.then(function () {
var rawData = item.get("rawData");
// If we have a rawData, delete it before Item
if (rawData && rawData.id) {
return rawData.destroy({
success: function (theObj) {
return item.destroy({
success: function (anotherObj) {
// I never pass here
return Parse.Promise.as();
},
error: function (anotherObj, error) {
// I never pass here
return Parse.Promise.as();
}
});
},
error: function (theObj, error) {
// I never pass here
return Parse.Promise.as();
}
});
} else {
return item.destroy({
success: function (anotherObj) {
// I never pass here
return Parse.Promise.as();
},
error: function (anotherObj, error) {
// I never pass here
return Parse.Promise.as();
}
});
}
});
});
return promise;
},
error: function (error) {
// I never pass here
return Parse.Promise.error(error);
}
}).then(function (nil) {
// I never pass here
return Parse.Promise.as("DELETEOLDITEMS: Job finished");
}, function(error) {
// I never pass here
return Parse.Promise.error(error);
});
}
(I have tested to replace every // I never pass here with console.log(), without any result)
I tried many different things but I believe this should work! Or at least return errors!
Anyone know what I am doing wrong? Thanks in advance!
EDIT:
Even weirder, if I modify performMaintenanceTasks to skip query.count():
function performMaintenanceTasks()
{
return deleteOldItems(1);
}
the query.find() in deleteOldItems() is correctly executed this time!
What does that mean? Am I not allowed to nest queries on the same class?
I'm not certain if this pertains to you, but I know from my a personal experience that the Parse log can seem a little unintuitive. The Parse log only spits out 10 lines by default, so ensure you're specifying the log length every time you check.
parse log -n 1000
...is what I tend to do every time. This just makes debugging easier.

Cloud code with many deletes in loop, but response.success finishes first on parse.com

I have a query, and they query may return many items.
I can go through all of them and destroy them.
The problem is since destroy is Async, the response.success(); part is executed before all the destroys are executed, so not all items are really deleted.
How can I make it wait until the loop is done and then only response.success();
Thanks.
garageQuery2.find({
success: function(results) {
alert("Successfully retrieved " + results.length + " garages to delete.");
// Do something with the returned Parse.Object values
for (var i = 0; i < results.length; i++) {
var object = results[i];
object.destroy({
success: function(myObject) {
// The object was deleted from the Parse Cloud.
},
error: function(myObject, error) {
// The delete failed.
// error is a Parse.Error with an error code and description.
}
});
}
response.success();
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
Try to work with Promises
This code is based on this: https://www.parse.com/docs/js_guide#promises-series
garageQuery2.find().then(function(results) {
// Create a trivial resolved promise as a base case.
var promiseSeries = Parse.Promise.as();
// the "_" is given by declaring "var _ = require('underscore');" on the top of your module. You'll use Underscore JS library, natively supported by parse.com
_.each(results, function(objToKill) {
// For each item, extend the promise with a function to delete it.
promiseSeries = promiseSeries.then(function() {
// Return a promise that will be resolved when the delete is finished.
return objToKill.destroy();
});
});
return promiseSeries;
}).then(function() {
// All items have been deleted, return to the client
response.success();
});
Hope it helps

Resources