Mongoose findOneAndUpdate updates the wrong item - mongodb

In my model I have a thread that contains an array of comments. When I try to update these comments it always updates the wrong one and I cannot figure out why.
Thread.findOneAndUpdate({
'comments._id': req.params.commentId,
'comments.created_by.user_id': user._id
},
{
$set: {
'comments.$.content': req.body.content,
}
}, { new: true }, (err, thread) => {
if(!err && thread){
res.status(200).json({success: true})
}
})
This code works, but it always updates the first comment rather than the one I am trying to update.

Related

mongo db findOneAndUpdate not returning document but updating it

findOneAndUpdate updates the document but returns with the error
collection.findOneAndUpdate(
{ verificationHash: req.query.hash },
{ $unset: {verificationHash: ''}}).then((err, user) => {//some code}
);
in this case my document is updated but user in callback is always undefined and content of error looks like
{
lastErrorObject: {n:1, updatedExisting: true},
value: document,
ok: 1
}
Am i missing something here or is this how the object in the callback is returned?
When executing .findOneAndUpdate in mongoDB then use {returnNewDocument: true} or if using mongoose you can use {new : true}
Set the returnNewDocument as true and you will get updated document.
collection.findOneAndUpdate(
{ verificationHash: req.query.hash }, // query
{ $unset: {verificationHash: ''}}, // update condition
{ returnNewDocument: true }, // returns updated document
function (err, documents) {
res.send({ error: err, affected: documents });
db.close();
}
)

Return only created subdocument mongoose

I need to push a new document into an array and use his _id.
Right now im using findOneAndUpdate, i know i can use { new: true } but i only need the created document and not the parent document.
this is my code so far
User.findOneAndUpdate(
{
'posts._id': req.params.id
},
{
$push: {
'posts.$.comments': {
from: {
_id: req.user._id,
username: req.user.username,
},
body: req.body.commentBody
}
}
},
err => {
if (err) console.log(err)
// Do something with ObjectId
}
);
Thanks in advance.
findOneAndUpdate callback gives you the updated document.
You have the Post's _id. You can use that to find the post to which you are adding the comment to. As you are pushing the comment, it will be the last element in the post array.
var mypost = doc.posts.find(function(post){
return post._id.toString()==req.params.id
});
console.log(mypost.comments[mypost.comments.length]._id)

Using async loop in mongodb shell for updating many documents

I have a problem with the following query in MongoDB shell ONLY when the size of the array gets bigger, for example, more than 100 elements.
newPointArray --> is an array with 500 elements
newPointArray.forEach(function(newDoc){
//update the mongodb properties for each doc
db.getCollection('me_all_test')
.update({ '_id': newDoc._id },
{ $set: { "properties": newDoc.properties } },
{ upsert: true });
})
Can someone guide me how can I run this query IN MongoDB SHELL for lager array by using an async loop or promise or...?
Thanks in advance
Rather than doing individual .update()s, use a .bulkWrite() operation. This should reduce the overhead of asking mongo to do multiple individual operations. This is assuming that you are doing general operations. I'm not clear on if newPointArray is always new points that don't exist.
Given your example, I believe your script would mimic the following:
// I'm assuming this is your array (but truncated)
let newPointArray = [
{
_id: "1",
properties: {
foo: "bar"
}
},
{
_id: "2",
properties: {
foo: "buzz"
}
}
// Whatever other points you have in your array
];
db
.getCollection("me_all_test")
.bulkWrite(newPointArray
// Map your array to a query bulkWrite understands
.map(point => {
return {
updateOne: {
filter: {
_id: point._id
},
update: {
$set: {
properties: point.properties
}
},
upsert: true
}
};
}));
You may also want to consider setting ordered to false in the operation which may also have performance gains. That would look something liked this:
db
.getCollection("me_all_test")
.bulkWrite([SOME_ARRAY_SIMILAR_TO_ABOVE_EXAMPLE], {
ordered: false
});

How to save / update multiple documents in mongoose

I am reading all documents of a specific schema from Mongoose. Now in my program I am doing some modifications to the results I got from Mongoose over time. Something like this:
var model = mongoose.model("Doc", docSchema);
model.find(function(err, result){
// for each result do some modifications
});
How can I send all the results back to the database to be saved? Currently I am iterating the documents and doing a save() on every document. I think there must be a better way. But currently I only find information on updating documents IN the database without returning them. Or bulk updates which do the SAME to update to each document.
You can use update query with multi:true which update all documents in your db.
please find below reference code,
model.update({ "_id": id }, { $set: { "Key": "Value" } }, { multi: true }, function (err, records) {
if (err || !records) {
return res.json({ status: 500, message: "Unable to update documents." });
} else {
return res.json({ status: 200, message: "success" });
}
});
If you are trying to make the same change to each document in the results, you could do something like this:
model.update({ _id: { $in: results.map(doc=>doc._id) }}, { yourField: 'new value' }, { multi: true })

insering a mongoose record if not found

The mongoose schema looks like:
var followSchema = new Schema({
userId: {type: String, required: true},
following : []
});
The Objective is to look for a user using the ID field and then add items to the following array.
The below method does not work:
var myRecord = FollowModel.findOneAndUpdate({userId: req.user.Id}, {upsert: true});
myRecord.exec(function(err, result) {
result.following.push('Test');
res.status(200).send('New Item Added to Follow List');
});
How is this to be done ?
It does work, you just forgot to include the { "new": true } option, as well as a valid update statment:
FollowModel.findOneAndUpdate(
{ "userId": req.user.Id},
{ "$setOnInsert": {
}},
{ "upsert": true, "new": true },
function(err,result) {
if (err) throw err;
console.log(result);
}
);
The blank $setOnInsert here will no nothing in this case, but otherwise you would put something in there that you wanted created "on insert". This would be applied along with any fields in the "query" portion of the statement.
Other standard update operators can also apply, but generally in the case where something "is" matched that you want to update.
But it's the { "new": true } here that lets the command know to return the "modified or created" document, rather than the "original or non existing" document, which is the default without that option.