OMGPOP
OMGPOP

Reputation: 984

parse.com Cloud Code prevent duplication error

I am following the instruction here:

https://parse.com/questions/unique-fields--2

var Profile = Parse.Object.extend("Profile");

Parse.Cloud.beforeSave("Profile", function(request, response) {

                       if (!request.object.get("entityID")) {
                            response.error('must have a entity id');
                       } else {

                       var query = new Parse.Query(Profile);
                       query.equalTo("entityID", request.object.get("entityID"));
                       query.first({

                                   success:function(object) {

                                    if (object) {
                                        response.error("already exist");
                                    }
                                    else {
                                        response.success();
                                    }

                                   },
                                   error:function(error) {
                                        response.error("couldnt validate uniqueness for this profile");
                                   }

                        });


                        }
                       });

I have a profile table and the unique key is entityID, when inserting, I need to check if the entry with the same key already exist.

The problem is, I am not able to update the entry anymore (it seems both insertion and update request trigger this cloud code.

How can i modify it so that

  1. when i insert, if it exists, I ignore it; if not exist, insert it.

  2. when i update, if it exist, update it; if not exist, i ignore it.

Upvotes: 2

Views: 2261

Answers (3)

Bluezen
Bluezen

Reputation: 860

S.C. is right.

In the meantime you could go dirty and do something like:

Parse.Cloud.afterSave("Profile", function(request) {

    // Find every Profile with same entityID
    var query = new Parse.Query(Profile);
    query.equalTo("entityID", request.object.get("entityID"));

    // Order them by creation in db (oldest in DB first)
    query.ascending("createdAt");

    query.find({

        success:function(results) {

            if (results && results.length > 1) {
                // We have a least one duplicate

                // Destroy every Profile except for the original (the oldest in DB)
                for(var i = (results.length - 1); i > 0 ; i--) {  
                    results[i].destroy();
                    // /!\ In case of concurrent call of afterSave, 
                    // we might run in situation of concurrent deletetion 
                    // of same Profile in this case we might encounter (or not?) some 
                    // time out of this function buuut we will always keep 
                    // the same Profile from being deleted.
                }
            }
            else {
                // No duplicates
            }

        },
        error:function(error) {
        }
     });
 });

Upvotes: 1

S.C.
S.C.

Reputation: 1160

I know this is kind of old, but it should be mentioned that until Parse either implements a lock/wait system or arbitrary constraint enforcement, it is not possible to cleanly prevent duplicate entries with cloud code since you are not guaranteed that only one instance of the code is running at any given point. Even if you have something like this:

if entry exists
    update it or don't add it
else
    add it

Since there is no locking, you cannot implement your own constraint enforcement. Also, attempting to do so will double your API calls and could bump you into a more expensive plan. The Parse staff has acknowledged this several times even in recent months (just search their forums) and suggests the use of atomic increments or the automatically generated unique object id for some circumstances, but for the most part this is not practical. They also suggest running automatic jobs to remove duplicates after they are entered, but this does not guarantee that at any given point the data in your system is internally consistent, even just after the job has run.

The bottom line is if constraint enforcement and overall data integrity are essential for your application, Parse is not yet mature enough to handle your needs. I hope to see this change soon.

Upvotes: 4

Dmitri Zaitsev
Dmitri Zaitsev

Reputation: 14056

Instead of using Create and Update requests, you can call your custom Cloud Function that does everything that you want. Saved me some headache.

Upvotes: 1

Related Questions