9

Is it possible to do nested queries in cloud code?

I want to be able to do something like

var adList = [];
var query2 = new Parse.Query("QR");
var query = new Parse.Query("Campaigns");
query.equalTo("isFeatured", true);

query.find({
success: function(results)  {
    for (var i=0; i<results.length; i++){
        var ad = [];
        ad.push(results[i].get("Type"));    //Adds "Type" to the ad array
        ad.push(results[i].id);     //gets the objectID and appends it to the arrayy

          //second INNER QUERY
        query2.equalTo("abc", true);
        adList.push(ad);
        query2.first({
            success: function(results){
                adList.push(5);
            },
            error: function(){
                response.error("inner fail");
            }
        });

    }

    response.success(adList);  //adds all ad arrays to adList array
},
error: function(){
    response.error("failed");
}   
});

I tried doing this, but the inner query never executes. Why?

3 Answers 3

14

The second query is asynchronous so wrapping it in a for won't work.

response.success gets triggered before the second query finished so you are returning before actually waiting for the results. I would tell you to move response.success inside of the second success callback of query2 but that won't work either since you are running an async operation synchronously inside a for so you will send the response in the first success.

Don't run an async operation inside a loop. It doesn't work.

I'm not sure what you are trying to accomplish here but you'll have to instantiate a new Query for every call if you want to make as many queries as results.

Again, I'm not sure what is exactly you are trying to do but here is a way you can do something like that:

    var adList = [];
    var query = new Parse.Query("Campaigns");
    query.equalTo("isFeatured", true);

    query.find({
        success: function(results)  {
            var queries = [];

            for (var i=0; i<results.length; i++){
                var query2 = new Parse.Query("QR");
                query2.equalTo("abc",true);

                var ad = [];
                ad.push(results[i].get("Type"));
                ad.push(results[i].id);
                adList.push(ad);
                queries.push(query2);
            }

            var totalLength = results.length;

            function makeQueries(qs){
                qs.shift().first({
                    success: function(currentResult) {
                        // do stuff with currentResult
                        if(qs.length){
                            makeQueries(qs);
                        } else {
                            console.log('We successfully made ' + totalLength + ' queries')
                            // we are done with the queries
                            response.success(adList);
                        }
                    },
                    error: function() {
                        response.error('Error in inner queries nº' + totalLength - qs.length)
                    }
                });
            }
            makeQueries(queries);
        },
        error: function(){
            response.error("failed");
        }
    });

Bar in mind that Parse Cloud Code let you run code for aprox 5/7 seconds and this might be very slow if you have a lot of results. Btw, take a look a Parse's matchesQuery method.

Example taken from their docs:

    var Post = Parse.Object.extend("Post");
    var Comment = Parse.Object.extend("Comment");
    var innerQuery = new Parse.Query(Post);
    innerQuery.exists("image");
    var query = new Parse.Query(Comment);
    query.matchesQuery("post", innerQuery);
    query.find({
      success: function(comments) {
        // comments now contains the comments for posts with images.
      }
    });        
Sign up to request clarification or add additional context in comments.

Comments

1

I think the below code might help someone,

var adList = [];
var query2 = new Parse.Query("QR");
var query = new Parse.Query("Campaigns");
query.equalTo("isFeatured", true);

query.find().then(function(results) {
    var _ = require('underscore');
    var promise = Parse.Promise.as();
    _.each(results, function(resultObj) { 
        var ad = [];
        ad.push(resultObj.get("Type"));    //Adds "Type" to the ad array
        ad.push(resultObj.id);     //gets the objectID and appends it to the arrayy

        //second INNER QUERY
        query2.equalTo("abc", true);
        adList.push(ad);
        return query2.first().then(function(results) {
            adList.push(5);
        });
    });
    return promise;
}).then(function() {
    response.success(adList);
}, function (error) {
    response.error("Error "+error.message);
});

Comments

0

I was able to cobble up the following answer. This works for me. Following the parse.com documentation guidelines for parallel promises. I create two promise arrays. One of them serves as promise array for inner loop. The other one serves as promise array for the outer loop.

Parse.Cloud.define("getFriends", function (request, response) {
  var _ = require('underscore.js');
  var queryFields = request.params.queryFields;
  //var ClassToSearch = Parse.Object.extend("User");

  var promises = [];
  var promises2 = [];
  var FinalResult = [];
 var asyncFunc = function (userIDArray) {
    _.each(queryFields, function (queryField) {
      var query = new Parse.Query(Parse.User);
      query.equalTo("yourColumnName", queryField);
      promises.push(
        query.find().then(function (results) {
       _.each(results, function (resultObj) { 
        //nested query
        var ClassToSearch = Parse.Object.extend("AnotherColumn");
        var query2 = new Parse.Query(ClassToSearch);
        query2.equalTo("yourColumnName", resultObj);
        promises2.push(        
          query2.first().then(function (itinerary) {
          FinalResults.push(itinerary);
        }));

      });
      return Parse.Promise.when(promises2);
    })
          )
    });
    // Return a new promise that is resolved when all of the requests are done 
    return Parse.Promise.when(promises);
  };
  asyncFunc(queryFields).then(function () {
    console.log("all http requests were made");
    response.success(FinalResults);
  }, function (error) {
    console.log("there was some error");
  });
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.