1

I have this code but I am unable to use this userArray outside of the for loop, not sure why it returns nothing, here is the 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) {
    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 queryFavourite = new Parse.Query(UserFavourite);
        queryFavourite.equalTo("item", item);
        queryFavourite.equalTo("school", school);
        queryFavourite.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);
                }
//                  console.log(userArray);
                return userArray;
            }
            return userArray;


        });            
        console.log('sadf '+userArray);
    }
    console.log('sadf '+userArray);
    return userArray;


}).then(function() {
    console.log(userArray);
});

I have taken a look at this but I still can seem to be able to get userArray in the last function or in the two console.log's before it

How do I return the response from an asynchronous call?

Thanks for the help in advance.

Community
  • 1
  • 1

3 Answers3

2

Note: This is not a tested code... but the solution is to use a promise which will be resolved once all the promises from the loop is completed

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 queryFavourite = new Parse.Query(UserFavourite);
        queryFavourite.equalTo("item", item);
        queryFavourite.equalTo("school", school);
        var prom = queryFavourite.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);
                }
                //                  console.log(userArray);
                return userArray;
            }
            return userArray;
        });
        promises.push(prom);
        console.log('sadf ' + userArray);
    }
    console.log('sadf ' + userArray);
    return Parse.Promise.when.apply(Parse.Promise, promises);
}).then(function () {
    console.log(userArray);
});

Here what we does is to create a array of promises in the loop, which will be passes to .when() to return a promise which will be resolved when all those promises passed to it will be completed.

So by definition the last then() should get the updated userArray - test and let me know whether it works

Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
2

What APJ says appears to be 100% correct, however by avoiding unnecessary assignments and with a combination of chaining and judicious use of array.map() and array.reduce(), you can get the volume of code down quite considerably.

People with their eyes attuned to array.map() and array.reduce(), may even find that readability is improved.

The heart of the pattern is :

(new Parse.Query(...))...find().then(function(results) {
    return Parse.Promise.when(results.map(function(obj) { // map results to a new array, and return it.
        return (new Parse.Query(...))...find().then(function(users) {
            return users.map(...); // map users to a new array, and return it.
        });
    })).then(function() {// each argument to this function is an array of ids
        // process `arguments` to form a single array of unique ids, and return it.
    });
});

In full :

Parse.Cloud.define("test", function(request, response) {
    (new Parse.Query(Parse.Object.extend("TestItem")))
        .limit(1000)
        .equalTo('school', 'Union College (NY)')
        .find().then(function(results) {
            return Parse.Promise.when(results.map(function(obj) {
                return (new Parse.Query(Parse.Object.extend("UserFavourite")))
                    .equalTo("item", obj.get('item'))
                    .equalTo("school", obj.get('school'))
                    .find().then(function(users) {
                        return users.map(function(user) {
                            return user.get('user').id; // duplicates are filtered out below
                        });
                    });
            })).then(function() {
                return Array.prototype.slice.apply(arguments).reduce(function(p, c) { // reduce an array of arrays to a single array
                    return p.concat(c);
                }).filter(function(value, idx, self) { // filter out duplicates
                    return self.indexOf(value) === idx;
                });
            });
    }).then(function(userArray) { // named member `userArray` appears for the first time at this point
        console.dir(userArray);
    });
});

untested

You will see that the desired array is not composed directly but derived from an array of promises, each of which delivers an array of userIDs.

Performance-wise, there are pluses and minuses in adopting this approach. Without testing, I couldn't say which way it would go.

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
  • could you say what some of the pluses and minuses could be? possibly? –  Sep 01 '14 at 17:16
  • The performance pluses will be mainly due to less interaction with the symbol table; ie no overt assignments (though assignments may still be made inside the library methods). The minuses will be due to using `.map()` instead of `for` loops, and the need to reduce and filter the data delivered by the promises. Overall, I would guess the minuses would predominate - performance would be poorer. – Roamer-1888 Sep 01 '14 at 17:44
  • That said, performance is not really an issue unless your 'results' and 'users' have thousands of members. Up to mere hundreds, you really won't notice the difference. So for low volumes, I would accept the (probably) poorer performance and enjoy the compactness of the code. – Roamer-1888 Sep 01 '14 at 17:44
0

You need to change this

then(function() {
            return Array.prototype.slice.apply(arguments).reduce(function(p, c) { // reduce an array of arrays to a single array
                return p.concat(c);
            }).filter(function(value, idx, self) { // filter out duplicates
                return self.indexOf(value22) === idx;
            });

To

then(function() {
            return Array.prototype.slice.apply(arguments).reduce(function(p, c) { // reduce an array of arrays to a single array
                return p.concat(c);
            }).filter(function(value, idx, self) { // filter out duplicates
                return self.indexOf(value2) === idx;
            });