Search code examples
javascriptparse-platformpromiseparse-cloud-code

Difference between Parse.Object.saveAll(objects) and Parse.Promise.when(promiseListOfSaves)


I've got a cloud code function which marks Notification objects as "read" and then queries the same class immediately for remaining "unread" objects.

The problem is the most times, the same Notification objects I mark as read are returned in my preceding unread query, even if the values have been updated in data browser.

When I changed from Parse.Promise.when() to Parse.Object.saveAll(), that solved the issue, but it's still unclear why. The when promise is supposed to be resolved when all the save() operations complete and hence will not run the last "unread" query until they've been marked as read.

What does Parse.Object.saveAll(objects) do that Parse.Promise.when(promiseListOfSaves) doesn't?

Code examples of each below. Not much difference between the two aside from the way objects are being saved.

Parse.Cloud.define('markThreadReadAndReturnUnreadCount', function(request, response){

    var promiseChain = [];
    var Notification = Parse.Object.extend("Notification");
    qry = new Parse.Query(Notification);
    qry.equalTo('owner', request.user);
    qry.equalTo('read', false);
    qry.equalTo('messageThreadId', request.params.threadId);
    qry.find(null, {useMasterKey: true}).then(function(_notifications){
        _.each(_notifications, function(_notification){
            notification = new Notification();
            notification.id = _notification.id;
            notification.set('read', true);
            promiseChain.push(notification.save(null, {wait: true}));
        });
        return Parse.Promise.when(promiseChain);
    }).then(function(){
        var countUnreadQuery = new Parse.Query(Notification);
        countUnreadQuery.equalTo('owner', user);
        countUnreadQuery.equalTo('read', false);
        countUnreadQuery.find({useMasterKey: true}).then(function(results){
            return response.success(results.length);
        }
    };

});

with Parse.Object.saveAll();

Parse.Cloud.define('markThreadReadAndReturnUnreadCount', function(request, response){

    var saveObjects = [];
    var Notification = Parse.Object.extend("Notification");
    qry = new Parse.Query(Notification);
    qry.equalTo('owner', request.user);
    qry.equalTo('read', false);
    qry.equalTo('messageThreadId', request.params.threadId);
    qry.find(null, {useMasterKey: true}).then(function(_notifications){
        _.each(_notifications, function(_notification){
            notification = new Notification();
            notification.id = _notification.id;
            notification.set('read', true);
            saveObjects.push(notification);
        });
        return Parse.Object.saveAll(saveObjects);
    }).then(function(){
        var countUnreadQuery = new Parse.Query(Notification);
        countUnreadQuery.equalTo('owner', user);
        countUnreadQuery.equalTo('read', false);
        countUnreadQuery.find({useMasterKey: true}).then(function(results){
            return response.success(results.length);
        }
    };

});

Solution

  • I am not sure why saveAll works where when doesn't work, but I would prefer saveAll over when in this scenario for two reasons:

    1. The code style, what looks better of the two options below:

      function save(objects){
          return Parse.Promise.when(objects.map(function(object){
              return object.save(null, {wait: true});
          }));
      }
      
      // or
      
      function save(objects){
          return Parse.Object.saveAll(objects);
      }
      
    2. Performance, when you use an array of save, you send n http requests for the n objects you want to save, this is a huge waste of resources, but when you use saveAll you send only one request for all of them.

    also I think your second code can be reduced to:

    ...
    qry.find(null, {useMasterKey: true}).then(function(_notifications){
        _.each(_notifications, function(_notification){
            notification.set('read', true);
        });
        return Parse.Object.saveAll(_notifications);
    }).then(function(){
    ...