javascriptparse-platformparse-cloud-codebefore-save

How to query objects in the CloudCode beforeSave?


I'm trying to compare a new object with the original using CloudCode beforeSave function. I need to compare a field sent in the update with the existing value. The problem is that I can't fetch the object correctly. When I run the query I always get the value from the sent object.

UPDATE: I tried a different approach and could get the old register ( the one already saved in parse). But the new one, sent in the request, was overridden by the old one. WHAT?! Another issue is that, even thought the code sent a response.success(), the update wasn't saved. I believe that I'm missing something pretty obvious here. Or I'm facing a bug or something...

NEW APPROACH

Parse.Cloud.beforeSave('Tasks', function(request, response) {
  if ( !request.object.isNew() )
  {
    var Task = Parse.Object.extend("Tasks");
    var newTask = request.object;
    var oldTask = new Task();
    oldTask.set("objectId", request.object.id);
    oldTask.fetch()
        .then( function( oldTask )
    {
        console.log(">>>>>> Old Task: " + oldTask.get("name") + " version: " + oldTask.get("version"));
        console.log("<<<<<< New Task: " + newTask.get("name") + " version: " + newTask.get("version"));
        response.success();
    }, function( error ) {
            response.error( error.message );
        }
    );
    }
});

OBJ SENT {"name":"LLL", "version":333}

LOG

 I2015-10-02T22:04:07.778Z]v175 before_save triggered for Tasks for user tAQf1nCWuz:
 Input: {"original":{"createdAt":"2015-10-02T17:47:34.143Z","name":"GGG","objectId":"VlJdk34b2A","updatedAt":"2015-10-02T21:57:37.765Z","version":111},"update":{"name":"LLL","version":333}}
 Result: Update changed to {}
 I2015-10-02T22:04:07.969Z]>>>>>> Old Task: GGG version: 111
 I2015-10-02T22:04:07.970Z]<<<<<< New Task: GGG version: 111

NOTE: I'm testing the login via cURL and in the parse console.

CloudCode beforeSave

Parse.Cloud.beforeSave("Tasks", function( request, response) {
  var query = new Parse.Query("Tasks");
  query.get(request.object.id)
    .then(function (oldObj) {
        console.log("-------- OLD Task: " + oldObj.get("name") + " v: " + oldObj.get("version"));
        console.log("-------- NEW Task: " + request.object.get("name") + " v: " + request.object.get("version"));
    }).then(function () {
        response.success();
    }, function ( error) {
        response.error(error.message);
    }
  );
});

cURL request

curl -X PUT \
-H "Content-Type: application/json" \
-H "X-Parse-Application-Id: xxxxx" \
-H "X-Parse-REST-API-Key: xxxxx" \
-H "X-Parse-Session-Token: xxxx" \
-d "{\"name\":\"NEW_VALUE\", \"version\":9999}" \
https://api.parse.com/1/classes/Tasks/VlJdk34b2A

JSON Response

"updatedAt": "2015-10-02T19:45:47.104Z"

LOG The log prints the original and the new value, but I don't know how to access it either.

I2015-10-02T19:57:08.603Z]v160 before_save triggered for Tasks for user tAQf1nCWuz:
Input: {"original":{"createdAt":"2015-10-02T17:47:34.143Z","name":"OLD_VALUE","objectId":"VlJdk34b2A","updatedAt":"2015-10-02T19:45:47.104Z","version":0},"update":{"name":"NEW_VALUE","version":9999}}
Result: Update changed to {"name":"NEW_VALUE","version":9999}
I2015-10-02T19:57:08.901Z]-------- OLD Task: NEW_VALUE v: 9999
I2015-10-02T19:57:08.902Z]-------- NEW Task: NEW_VALUE v: 9999

Solution

  • After a lot test and error I could figure out what was going on.

    Turn out that Parse is merging any objects with the same class and id into one instance. That was the reason why I always had either the object registered in DB or the one sent by the user. I honestly can't make sense of such behavior, but anyway...

    The Parse javascript sdk offers an method called Parse.Object.disableSingeInstance link that disables this "feature". But, once the method is called, all object already defined are undefined. That includes the sent object. Witch means that you can't neither save the sent object for a later reference.

    The only option was to save the key and values of the sent obj and recreate it later. So, I needed to capture the request before calling disableSingleInstance, transform it in a JSON, then disable single instance, fetch the object saved in DB and recreate the sent object using the JSON saved.

    Its not pretty and definitely isn't the most efficient code, but I couldn't find any other way. If someone out there have another approach, by all means tell me.

    Parse.Cloud.beforeSave('Tasks', function(request, response) {
      if ( !request.object.isNew() ) {
        var id = request.object.id;
        var jsonReq;
        var Task = Parse.Object.extend("Tasks");
        var newTask = new Task;
        var oldTask = new Task;
    
        // getting new Obj
        var queryNewTask = new Parse.Query(Task);
        queryNewTask.get(id)
            .then(function (result) {
                newTask = result;
    
                // Saving values as a JSON to later reference
                jsonReq = result.toJSON();
    
                // Disable the merge of obj w/same class and id
                // It will also undefine all Parse objects,
                // including the one sent in the request
                Parse.Object.disableSingleInstance();
    
                // getting object saved in DB
                oldTask.set("objectId", id);
                return oldTask.fetch();
            }).then(function (result) {
                oldTask = result;
    
                // Recreating new Task sent
                for ( key in jsonReq ) {
                    newTask.set( key, jsonReq[key]);
                }
    
                // Do your job here
            }, function (error) {
                response.error( error.message );
            }
        );
      }
    });