Avoid extra query with Mongo and Express in PUT - node.js

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.

Related

How to check if a document exisits in MongoDB

I am trying to check if a document exists in MongoDB and then based on that either update the document or create a new one. However only the if statement is being recorded. I have checked that the value of documentExists is null if no document is in mongo.
router.post("/mongo", async function (req, res) {
const documentExists = await Files.findOne({
_id: req.body.id,
});
if (documentExists) {
try {
Files.updateOne(
{ _id: documentExist._id },
{ flag: req.body.flag },
function (err, result) {
if (err) {
res.send(err);
} else {
res.send(result);
}
}
);
} catch (err) {
res.status(400).send(err);
}
} else {
CREATE NEW DOCUMENT
}
})
In your case you can use findOneAndUpdate to update if there is any existing document in the collection, if there is no matching document the query returns null.

find and modify obejct in mlab collection by _id with nodejs

i am posting an object to update the current one. Searching by id and replacing it. For some reason i don't get errors but the mlab object is not updated. Am i missing something?
app.post("/api/updateCheck", function (req, res) {
console.log('updating', req.body);
conn.collection("checks").findAndModify({
_id: req.body._id
}, {$set: req.body}, {}, function(err,doc) {
if (err) { console.log(err) }
else { console.log("Updated"); }
});
});
got it. updateOne seems to work. I am posting a check object and retrieving id from it to search the collection and update content accordingly.
// modify content
app.post("api/updateCheck", function(req, res) {
console.log("updating", req.body);
conn.collection("checks").updateOne(
{
_id: new ObjectId(req.body._id)
},
{
$set: {
content: req.body.content
}
},
function(err, doc) {
if (err) {
console.log("error", err);
} else {
console.log('success', doc.modifiedCount);
console.log('??', doc.matchedCounted);
res.status(200).json(res.body);
}
}
);
});

mongoose findOne work using id instead of _id

I was stuck for a while when I do _id in findOne function I got empty result.
exports.getUser = function(req, res) {
User.findOne({id: req.params.id}, function(err, user) {
if (err) {
return res.status(400).send({
msg: err
})
} else {
return res.json({status:1, data: user})
}
})
}
Above code worked but I'm curious why this won't work
...
User.findOne({_id: req.params.id}, function(err, user) {
...
I think I have to parse req.params.id with ObjectId function, but is there any global method that ignore this rule? for me it make sense just use _id: myId

Mongoose change document _id on save/update

a quick one:
Why is Mongoose change/upgrading the _id field of a document when I push an update?
Is this an intended behavior?
Thanks.
This is the update I use inside my PUT route, and it returns successfully the updated model, but unfortunately with a new _id for doc
Document.findById(req.params.doc_id, function (err, doc) {
if (err)
res.send(err)
// Do some subdoc stuff here …
doc.save(function (err) {
if (!err) {
console.log('Success!');
res.json(doc);
} else {
console.log(err);
}
});
});
Okay, problem solved:
I was logging the wrong _id (doh!)
Mongoose docs http://mongoosejs.com/docs/2.7.x/docs/model-definition.html
suggest using update or findOne
ex:
var query = { name: 'borne' };
Document.update({"_id": req.params.doc_id}, { name: 'jason borne' }, {}, function(err, numAffected){
if (!err) {
console.log('Success!');
res.json(numAffected);
} else {
console.log(err);
}
});
or
Model.findOne({ "_id": req.params.doc_id }, function (err, doc){
doc.name = 'jason borne';
doc.save();
// here you could use your save instead, but try not to use the doc again
// it is confusing
// doc.save(function (err, documentSaved, numberAffected) {
// if (!err) {
// console.log('Success!');
// res.json(documentSaved);
// } else {
// console.log(err);
// }
// });
});
Later I also found the findById update suggested in some docs http://mongoosejs.com/docs/documents.html, which seems to be up to date, check the version you are using and also double check the two times you are using doc in your functions here. Also you can check your mongoDB and see if there are more than one record getting saved.
db.documents.find( {} )

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

Resources