apply update options without save for pre-validation - mongoosejs - node.js

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);
});
});
});

Related

Execute three operations in Mongodb or cancel if just one fails

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.

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');
}
);

Document not saving after finding and modifying in Mongoose

I have a route to remove a team and all requests to join that specific team, which is nested in a JoinTeamRequests array in the UserProfiles. The idea is to remove all traces of invites to that team once it has been deleted. I am using the MEAN stack. I am still new at this so any other advice or suggestions would be great.
here is my route:
//Remove a specific team
.delete (function (req, res) {
//Delete the team - works
TeamProfile.remove({
_id : req.body.TeamID
}, function (err, draft) {
if (err)
res.send(err);
});
UserProfile.find(
function (err, allProfiles) {
for (var i in allProfiles) {
for (var x in allProfiles[i].JoinTeamRequests) {
if (allProfiles[i].JoinTeamRequests[x].TeamID == req.body.TeamID) {
allProfiles[i].JoinTeamRequests.splice(x, 1);
console.log(allProfiles[i]); //logs the correct profile and is modified
}
}
}
}).exec(function (err, allProfiles) {
allProfiles.save(function (err) { //error thrown here
if (err)
res.send(err);
res.json({
message : 'Team Successfully deleted'
});
});
});
});
However, I get an error: TypeError: allProfiles.save is not a function.
Why is it throwing this error?
First of all it is more common to perform search in next form:
UserProfile.find({'JoinTeamRequests.TeamID': req.body.TeamID})
Secondly, after execution you have to check if returned array is not empty:
if(allProfiles && allProfiles.length) {
}
I think it could be possible to execute this in one statement, but for now, try the next chunk of code:
UserProfile.find({'JoinTeamRequests.TeamID': req.body.TeamID}).exec(function (err, users) {
if(err) {
return res.end(err);
}
if(users && users.length) {
users.forEach(function(user) {
user.JoinTeamRequests.remove(req.body.TeamID);
user.save(function(err) {
if(err) {
return res.end(err);
}
})
});
}
});

Avoid extra query with Mongo and Express in PUT

I'm updating a record in Mongo with Mongoose/Express:
app.put('/loggedIn/:id', function(req, res) {
if (req.user._id == req.params.id) {
User.update({
_id: req.user._id
}, {
$set: {
interests: req.body.interests
}
}, function(err, num) {
if (err) return err;
User.findById(req.user._id, '_id username interests', function(err, user) {
if (err) return;
res.json(user);
});
});
} else {
console.log('fail');
}
});
How can I avoid doing the second query in the callback of the update(), seems a lot just to return the newly updated document.
If you're always updating only one document you can use findByIdAndUpdate (or findOneAndUpdate), which updates the document if found and returns it to the callback:
app.put('/loggedIn/:id', function(req, res) {
if (req.user._id == req.params.id) {
User.findByIdAndUpdate(req.user._id, {
$set: {
interests: req.body.interests
}
}, function(err, user) {
if (err) return;
res.json(user);
});
} else {
console.log('fail');
}
});
I think you can get the raw Mongo response as the 3rd update callback argument. Check if this contains what you want. Otherwise, try passing the option { raw: true }.
See http://mongodb.github.io/node-mongodb-native/markdown-docs/insert.html
You could use findByIdAndUpdate instead of a separate find and update.
I also sometimes do User.Find() and then inside the success callback Doc.save(). That lets you do more complex things between if it's not just a straight update from the request.

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