Parse cloudcode beforeSave obtain pre-updated object
Asked Answered
S

5

12

In a beforeSave hook I want to obtain the state of the object prior to the update. In this particular case it is to stop a user from changing their choice once they have made it. Pseudo-code looks something like:

If (user has already voted) {
  deny;
} else {
  accept;
}

And the code that I have so far is:

Parse.Cloud.beforeSave('votes', function(request, response) {
  if (!request.object.isNew()) {
    // This is an update.  See if the user already voted
    if (request.object.get('choice') !== null) {
      response.error('Not allowed to change your choice once submitted');
    }
  }
  response.success();
}

But request.object is the state of the object with the update already applied.

Note that the 'votes' object is created separately so this isn't allowing an insert but not an update will not suffice; I need to know if a given field is already set in the database.

Slipon answered 1/8, 2014 at 14:16 Comment(0)
W
9

The request variable is the updated row itself. You can get it's object id through request.object.idand use this to grab the current row from the database and check the current value, like so:

Parse.Cloud.beforeSave('votes', function(request, response) {
    if (!request.object.isNew()) {
    var query = new Parse.Query("votes");
    query.get(request.object.id, { // Gets row you're trying to update
        success: function(row) {
            if (row.get('choice') !== null) 
                response.error('Not allowed to change your choice once submitted');
            response.success(); // Only after we check for error do we call success
        },
        error: function(row, error) {
            response.error(error.message);
        }
    });
}
Weyermann answered 1/8, 2014 at 14:44 Comment(2)
Thanks; was hoping that they automatically gave you the prior object but this will work just fine.Slipon
One minor note for those finding this response: line 6 of the answer above row.object.get('choice') should just be row.get('choice')Slipon
F
16

While Krodmannix's response is correct (and was helpful to me) it has the overhead of a full query. If you are doing things in beforeSave, you really want to streamline them. As a result, I believe a fetch command is much preferable.

Parse.Cloud.beforeSave('votes', function(request, response) {
    if (!request.object.isNew()) {
      var Votes = Parse.Object.extend("votes");
      var oldVote = new Votes();
      oldVote.set("objectId",request.object.id);
      oldVote.fetch({
        success: function(oldVote) {
            if (oldVote('choice') !== null) {
                response.error('Not allowed to change your choice once submitted');
            }
            else {
                response.success(); // Only after we check for error do we call success
            }
        },
        error: function(oldVote, error) {
            response.error(error.message);
        }
    });
});
Fatwitted answered 30/9, 2014 at 15:38 Comment(1)
Hi @MobileVet. I'm having a similar problem. But in my case I need to fetch the old and the new objects and compare its values, and then save(or not). The problem is that I can only fetch the new or the old. Take a look at my question at: https://mcmap.net/q/909524/-how-to-query-objects-in-the-cloudcode-beforesave/4871489 tksGigi
E
12

If you are using the self hosted Parse Server, there is a property on request called "original" that is the object before changes.

Parse.Cloud.beforeSave("Post", function(request, response) {
    console.log(request.object);    //contains changes
    console.log(request.original);  //contains original
    response.success();
});
Elviraelvis answered 5/4, 2017 at 23:51 Comment(0)
C
10

You can use Parse DirtyKeys to identify which field has changed.

   Parse.Cloud.beforeSave(Parse.User, function(request, response) {
  for (dirtyKey in request.object.dirtyKeys()) {
    if (dirtyKey === "yourfieldname") {
      response.error("User is not allowed to modify " + dirtyKey);
      return;
    }
  }
  response.success();
});
Coquet answered 4/11, 2014 at 2:42 Comment(3)
dirtyfield contains every field that is either has a new valye or updated value. In case of a new object, all the fields are dirty. But you dont need to use dirtykey to check for new object. You can simply do if(request.object.existed()) check to identify if its a new object.Coquet
Also u can check is the object is new using "request.object.isNew()"Dewyeyed
Please note the example code is wrong in using for in. It has to be` for of` for (const dirtyKey of request.object.dirtyKeys()) { // this will give keys correctlyDuchess
W
9

The request variable is the updated row itself. You can get it's object id through request.object.idand use this to grab the current row from the database and check the current value, like so:

Parse.Cloud.beforeSave('votes', function(request, response) {
    if (!request.object.isNew()) {
    var query = new Parse.Query("votes");
    query.get(request.object.id, { // Gets row you're trying to update
        success: function(row) {
            if (row.get('choice') !== null) 
                response.error('Not allowed to change your choice once submitted');
            response.success(); // Only after we check for error do we call success
        },
        error: function(row, error) {
            response.error(error.message);
        }
    });
}
Weyermann answered 1/8, 2014 at 14:44 Comment(2)
Thanks; was hoping that they automatically gave you the prior object but this will work just fine.Slipon
One minor note for those finding this response: line 6 of the answer above row.object.get('choice') should just be row.get('choice')Slipon
N
0

This Worked :

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);
        });
Noh answered 17/9, 2016 at 8:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.