Reputation: 35306
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:
What is the "ultimate way" to prevent duplication with Parse server?
Upvotes: 3
Views: 850
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
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
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
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