quarks
quarks

Reputation: 35306

The ultimate way to prevent duplication in Parse Server once and for all

One of the biggest issue we face now with parse-server is duplication. Although we have implemented a Parse cloud code to prevent such event through beforeSave and afterSave methods at the same time added external middleware to check for existing object before saving still we face duplication over and over specially on concurrent operations.

Here is our code to prevent duplication for a specific class:

Parse.Cloud.beforeSave("Category", function(request, response) {
    var newCategory = request.object;
    var name = newCategory.get("name");
    var query = new Parse.Query("Category");
    query.equalTo("name", name);
    query.first({
        success: function(results) {
            if(results) {
                if (!request.object.isNew()) { // allow updates
                    response.success();
                } else {
                    response.error({errorCode:400,errorMsg:"Category already exist"});
                }
            } else {
                response.success();
            }
        },
        error: function(error) {
            response.success();
        }
    });
});
Parse.Cloud.afterSave("Category", function(request) {
    var query = new Parse.Query("Category");
    query.equalTo("name", request.object.get("name"));
    query.ascending("createdAt");
    query.find({
        success:function(results) {
            if (results && results.length > 1) {
                for(var i = (results.length - 1); i > 0 ; i--) {
                    results[i].destroy();
                }
            }
            else {
                // No duplicates
            }
        },
        error:function(error) {
        }
    });
});

This code above is able to prevent some duplicate but most still goes through, example:

enter image description here

What is the "ultimate way" to prevent duplication with Parse server?

Upvotes: 3

Views: 850

Answers (4)

Mr.Tobie
Mr.Tobie

Reputation: 21

Not sure if this is still needed, but I recently had the same problem. As already answered here (but without explanation) the query.first() call is asynchronous, you need to await the response. The correct code could then looks like this:

Parse.Cloud.beforeSave('Category', async (request) => {
   const newEntry = request.object;
   const teamId = newEntry.get('name');
   const query = new Parse.Query('Category');
   query.equalTo('name', name);

   //check database for entries
   const results = await query.count();

   if (results === 0) {
      //no existing entries
   } else {
      //there are already existing entries
      throw('Category already exist');
   }
});

Though it needs to be said, that using the query.first() function might be better for performance as it stops after the first entry. However, I find this approach to be easier to understand and should not be noticeable faster if your DB is not gigantic.

Furthermore the afterSave function is then superfluous and can be removed.

Upvotes: 1

a6b8
a6b8

Reputation: 11

Here is my Solution:

Parse.Cloud.beforeSave( 'ClassName', async ( request ) => {
    const columnName = 'columnName'
    const className = 'ClassName'

    if( request.object.isNew() ) {
        var newCategory = request.object
        var name = newCategory.get( columnName )
        var query = new Parse.Query( className )
        query.equalTo( columnName, name )
    
        const results = await query.count()

        if( results === 0 ) {
            // no response.success needed 
            // https://github.com/parse-community/parse-server/blob/alpha/3.0.0.md
        } else {
            throw 'Is not unique'; 
        }
    }
} )

Upvotes: 1

Yannick Lorenz
Yannick Lorenz

Reputation: 1

Maybe you should write something with Promises like :

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


    return new Promise((resolve, reject) => {

        var query = new Parse.Query("Category");
        query.equalTo("name", "Dummy");

        return query.first().then(function (results) {

            resolve(); // or reject()
        });
    })

});


Parse.Cloud.beforeSave("Category", async (request) => {

    (...)
    await results = query.first();

    // then your logic here
    response.success();
    response.error({ errorCode: 400, errorMsg: "Category already exist" })

})

Upvotes: 0

flovilmart
flovilmart

Reputation: 1769

You can always create a unique index in mongodb for the field that should be unique in your document.

This way any save that conflicts with that index, will be aborted

Upvotes: 7

Related Questions