I\'m trying to compare a new object with the original using CloudCode beforeSave function. I need to compare a field sent in t
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 );
}
);
}
});
Rather than performing a query, you can see the modified attributes by checking which keys are dirty, meaning they have been changed but not saved yet.
The JS SDK includes dirtyKeys()
, which returns the keys that have been changed. Try this out.
var attributes = request.object.attributes;
var changedAttributes = new Array();
for(var attribute in attributes) {
if(object.dirty(attribute)) {
changedAttributes.push(attribute);
// object.get(attribute) is changed and the key is pushed to the array
}
}
For clarification, to get the original attribute's value, you will have to call get()
to load those pre-save values. It should be noted that this will count as another API request.
If I were you, I would pass in the old value as a parameter to the cloud function so that you can access it under request.params.(name of parameter). I don't believe that there is another way to get the old value. An old SO question said that you can use .get(), but you're claiming that that is not working. Unless you actually already had 9999 in the version...
edit - I guess beforeSave isn't called like a normal function... so create an "update version" function that passes in the current Task and the version you're trying to update to, perhaps?
Hey this worked perfectly for me :
var dirtyKeys = request.object.dirtyKeys();
var query = new Parse.Query("Question");
var clonedData = null;
query.equalTo("objectId", request.object.id);
query.find().then(function(data){
var clonedPatch = request.object.toJSON();
clonedData = data[0];
clonedData = clonedData.toJSON();
console.log("this is the data : ", clonedData, clonedPatch, dirtyKeys);
response.success();
}).then(null, function(err){
console.log("the error is : ", err);
});