Execute three operations in Mongodb or cancel if just one fails - node.js

I need to store one record in three different collections at the same time, but I need that if just one of this operations fails (for any kind of reasons) the entire procedure will be canceled. In a few words, I need to be sure that this record is stored correctly in each all the three collections: I need to avoid the situation where the record is stored in just two (or one) collections.
This is my actual code:
var insertOne = function(data) {
req.app.locals.db.collection('document_1').findOneAndUpdate({'id': data.id}, {$set: {'element': 'data.element}}, {returnOriginal: false}, function(err, result) {
if (err) {
console.log('error 1');
return;
}
if(result) insertTwo(data);
});
}
var insertTwo = function(data) {
req.app.locals.db.collection('document_2').findOneAndUpdate({'id': data.id}, {$set: {'element': 'data.element}}, {returnOriginal: false}, function(err, result) {
if (err) {
console.log('error 2');
return;
}
if(result) insertThree(data);
});
}
var insertThree = function(data) {
req.app.locals.db.collection('document_2').findOneAndUpdate({'id': data.id}, {$set: {'element': 'data.element}}, {returnOriginal: false}, function(err, result) {
if (err) {
console.log('error 3');
return;
}
if(result) console.log('success!');
});
}
insertOne(mydata);
Thanks.

Related

Finish execution if first query returns a value Node.js Express.js mongoDB

Before starting, please mind that i have been searching this over 2+ hours, the answer will be simple i know but i couldnt get it to work . i am new to express node mongodb,
MongoClient.connect(url, function(err, db) {
if (err) {
res.status(err.status); // or use err.statusCode instead
res.send(err.message);
}
var usernameGiven = req.body.usernameGiven;
//Select the database
var dbo = db.db("notifellow");
//run the query
var query = { username: usernameGiven , friends: []};
dbo.collection("users").findOne({ username: usernameGiven}, function(err, result) {
if (err){
res.status(err.status); // or use err.statusCode instead
res.send(err.message);
console.log("Query Error Occured!");
}
else {
if (result) {
//Send the response
res.send("EXISTS");
//I WOULD LIKE TO EXIT IF THIS LINE EXECUTES
}
}
});
dbo.collection("users").insertOne(query, function(err, result) {
if (err){
res.status(err.status); // or use err.statusCode instead
res.send(err.message);
console.log("Query Error Occured!");
}
else {
if (result) {
//Send the response
res.send("CREATED 201");
} else {
res.send("Failed to insert");
}
}
});
db.close();
});
my goal is to check if an user doesnt exists with given username, i would like to insert that to the DB.
i would like to exit if my query finds an match and arrange such that insertOne wont execute. please enlighten me!!
Once you are not using the async/await syntax you will have to nest the calls to MongoDB, so they execute in series. You can also use a module like async to achieve this.
MongoClient.connect(url, function(err, db) {
if (err) {
res.status(err.status); // or use err.statusCode instead
res.send(err.message);
}
var usernameGiven = req.body.usernameGiven;
//Select the database
var dbo = db.db("notifellow");
//run the query
var query = { username: usernameGiven , friends: []};
dbo.collection("users").findOne({ username: usernameGiven}, function(err, result) {
if (err){
res.status(err.status); // or use err.statusCode instead
db.close();
console.log("Query Error Occured!");
return res.send(err.message);
}
if (result) {
db.close();
return res.send("EXISTS");
}
dbo.collection("users").insertOne(query, function(err, result) {
if (err){
res.status(err.status); // or use err.statusCode instead
db.close();
console.log("Query Error Occured!");
return res.send(err.message);
}
db.close();
if (result) {
return res.send("CREATED 201");
}
res.send("Failed to insert");
});
});
});
Try this
dbo.collection("users").findOne({ username: usernameGiven}, function(err, result) {
if (err){
//put the error logic
}
else {
if (result) {
//Send the response
return result;
}
else{
// if above if block fails it means that user does not exist
//put the insert logic
}
});

How to find a record and insert the same record in Mongoose?

Here I want to get a record and I need to insert the same record with slight modification. But I can't see the data in my new record which I found in my get record. Here is what I tried, can anyone help me? I think the problem is with this line var institution = new Institution(data);:
Institution.find({_id:i._id}).exec(function (err, result) {
if(result)
transferData(result);
}
});
});
}
function transferData(data){
var institution = new Institution(data);
institution.name = 'xxxx';
institution.save(function (err, data) {
if (err) {
return res.status(400).send({ message: errorHandler.getErrorMessage(err) });
} else {
console.log('Data Inserted Successfully');
}
});
}
find() returns an array of docs that match the criteria in the callback hence the line
var institution = new Institution(data);
will not work as it's expecting a Document not an array.
You could use findById() method as:
Institution.findById(i._id).exec(function (err, result) {
if (result) transferData(result);
});
function transferData(data) {
var institution = new Institution(data);
institution.name = 'xxxx';
institution.save(function (err, data) {
if (err) {
return res.status(400).send({ message: errorHandler.getErrorMessage(err) });
} else {
console.log('Data Inserted Successfully');
}
});
}
A much better approach would involve the findByIdAndUpdate() method:
Institution.findByIdAndUpdate(i._id, {name: 'xxxx'}, {upsert: true}, function (err, data) {
if (err) {
return res.status(400).send({ message: errorHandler.getErrorMessage(err) });
} else {
console.log('Data Inserted Successfully');
}
);

Node.js : res.redirect("back") got Error('Can\'t set headers after they are sent.');

I have a little problem on an express.js app.
Can't redirect back after several actions with callbacks.
My applications works with objects called "markers" and they are rated by "sub categories"
The goal of these actions is to merge 2 or more subcategories, move all markers from old to the new subcategoy, and finally, delete the old sub category.
Here is the code :
The action called after checked 2 or more subcategories :
exports.postMergeSubCategories = function(req, res) {
"use strict";
var data = {};
data.subCategories = req.body.subCategoriesChecked;
data.enName = req.body.subCategory.enName;
data.frName = req.body.subCategory.frName;
data.deName = req.body.subCategory.deName;
if (data.subCategories.length > 1) {
sscategoryMapper.merge(data, function(err, sscategory) {
if (err) return console.log(err);
console.log ('Sub categories merged !');
req.flash('mergeMessage', 'Merge completed!');
res.redirect("back");
});
} else { // error
console.log('Error while merge sub categories. It seems the number of sub categories checked less 2');
req.flash('mergeMessage', 'An error occured whil merge');
res.redirect("back");
}
};
The function sscategoryMapper.merge :
module.exports.merge = function(data, callback) {
async.waterfall([
function(callback){ // create new sub category
save(data, function(err, sscategory) {
if (err) return callback(err);
callback(null, sscategory._id);
});
},
function(sscategoryId, callback){ // update marker2sscategory
async.each(data.subCategories.split('|'), function(oldSscategoryId, err) { // for each subcategories, update markers2sscategory and remove the old subcategory
async.waterfall([
function(callback) { // update maker2sscategory to set the new sscategoryId to all target markers
marker2sscategoryMapper.update(sscategoryId, oldSscategoryId, function(err) {
if (err) return callback(err);
callback(null, oldSscategoryId);
});
},
function(oldSscategoryId, callback) { // delete the old sscategory
remove(oldSscategoryId, function(err) {
if (err) return callback(err);
callback();
});
}
], function(err) {
if (err) return callback(err);
callback();
});
}, function(err) {
callback();
});
callback(null, sscategoryId);
}
], function (err, result) {
if (err) return callback(err);
callback(null, result);
});
};
UPDATE
First problem here : I called 2 times the callback ... This piece of code moved to that :
}, function(err) {
callback(null, sscategoryId);
});
}
], function (err, result) {
if (err) return callback(err);
callback(null, result);
});
};
UPDATE END
The function marker2sscategoryMapper.update :
module.exports.update = function(to, from, callback) {
// update marker2sscategory with the new subcategory
dbMarker2sscategory.update({'_sscategory' : from}, {
'_sscategory' : to
}, {multi: true}, function(err) {
if (err) return callback(new Error(err));
callback(null, to);
});
}
And the function remove :
var remove = module.exports.remove = function(id, callback) {
dbSscategory.remove({'_id' : id}, function(err) {
if (err) return callback(new Error(err));
callback(null, id);
});
};
If I comment "res.redirect("back")", it will works.
Else, the error is : "Error('Can\'t set headers after they are sent.');" 2 times.
I read that one of the causes can be duplicate callbacks ... But I don't see that in my code.
Appreciate your help.

apply update options without save for pre-validation - mongoosejs

In any webapp i press a plus button and a value will be increased.
When i hit the button fast the validation does not work, cause the validations does not prevent (excepted behavior, the value is not out of the validations range). But the value will be setted down further, cause the rest of the reqeust will be submitted.
Important: the update options are dynamically (for instance $inc or $set).
Current Code
module.model.update({ _id: id }, options /* are dynamic */, { safe: true }, function (err, updatedDocument) {
if (err) return respond(400, err);
module.model.findOne({ _id: id }, function (err, foundDocument) {
if (err) return respond(400, err);
foundDocument.validate(function (err) {
if (err) return respond(400, err);
return respond(200, foundDocument); // callback method
});
});
});
First guess to prevent the problem
module.model.findOne({ _id: id }, function (err, foundDocument) {
foundDocument.set(options);
foundDocument.validate(function (err) {
if (err) return respond(400, err);
foundDocument.save(function (err, savedDocument) {
if (err) return respond(400, err);
return respond(200, doc);
});
});
});
...then the save just will preformed when the validation is valid.
But there is a porblem: The set method does not support $inc or other pseudo setters, or does it?
I saw the possibility to use the constructor of the update function (Show Code), but i don't know how to use it: this.constructor.update.apply(this.constructor, args);
Do you have any good practise for this problem ?
The solution was to create a customized version for $inc.
What i've done is to replace the set method of mongoosejs.
This is now extendable, but a quiet custom way to validate before an update. When someone have another solution. Post it please.
module.model.findOne({ _id: id }, function (err, foundDocument) {
for(var optionsProp in options) {
if(optionsProp === '$inc') {
for(var incProp in options[optionsProp]) {
foundDocument[incProp] += options[optionsProp][incProp];
}
}
}
foundDocument.validate(function (err) {
if (err) return respond(400, err);
foundDocument.save(function (err, savedDocument) {
if (err) return respond(400, err);
return respond(200, savedDocument);
});
});
});

Unable to retrieve value from PouchDB

After inserting data using PouchDB I tried db.getAll() to retrieve all the documents and db.get() for single documents but none of the objects returned contained the value I was inserted in.
What am I doing wrong?
new Pouch('idb://test', function(err, db) {
doc = {
test : 'foo',
value : 'bar'
}
db.post(doc, function(err, data) {
if (err) console.error(err)
else console.log(data)
})
db.allDocs(function(err, data) {
if (err) console.error(err)
else console.log(data)
})
})
Your allDocs query is running before you have completed inserting the data into PouchDB, due to the IndexedDB API all database queries are asynchronous (they likely would have to be anyway as it's also a HTTP client).
new Pouch('idb://test', function(err, db) {
var doc = {
test : 'foo',
value : 'bar'
};
db.post(doc, function(err, data){
if (err) {
return console.error(err);
}
db.allDocs(function(err, data){
if (err) console.err(err)
else console.log(data)
});
});
});
... should work.

Resources