Mongoose update first five documents - node.js

Hello I am trying to update only first five documents from my schema using mongoose. I found a way to update documents by giving condition but cant update only first five.
I got this code
mongoose.model('person').update( {active:false} , {multi: true} , function(err,docs) { ... });
Thank you

The key here is to get the first 5 _id values matching your condition and then pass those using $in to your update selection:
mongoose.model('person').find({ "active": { "$ne": false }}).limit(5)
.exec(function(err,docs) {
var ids = docs.map(function(doc) { return doc._id } );
mongoose.model('person').update(
{ "_id": { "$in": ids } },
{ "$set": { "active": false } },
{ "multi": true },
function(err,numAffected) {
}
);
});
Also notice the correct arguments to the update statement with a "query" and "update" block. You should also be using update operators such as $set, otherwise you are overwriting the existing document content with just the contents of the "update"block.
Also see the .update() method from the core documentation.

Related

How to upsert a Hashmap into MongoDB Document?

I'm trying to structure a friendslist using MongoDB.
This is how I currently have it structured:
{
"_id": {
"$oid": "601c570da04b75fabcd2705d"
},
"user_id": 1,
"friendslist": {
3 : true
}
}
How can I create a query that does a put on my Hashmap (The hashmap is "friendslist") and the key is 3 for the friend's id and the true flag is for the status of the pending friend request. (True meaing they are friends and false would be pending friend request)
This is what I currently have:
const upsertFriendId = db.collection('friends')
.updateOne(
{ user_id: userId },
{ $set: { ???? : ????} },
{ upsert: true }
);
I can't figure out the syntax that I need to put in the $set object.
In-order to ensure that you do not override the rest of the keys inside the friendlist, you can do an update like
const mongoFriendKey = `friendlist.${/* FRIEND_ID_VARIABLE_GOES_HERE */}`;
const upsertFriendId = db.collection('friends')
.updateOne(
{
user_id: userId
},
{
$set:
{
[mongoFriendKey] : true
}
},
{ upsert: true }
);
In the above, replace the /* FRIEND_ID_VARIABLE_GOES_HERE */ with the friend id variable. Doing that, the query will look for a friend with that specific Id, and then it will try to set it to true if not found, without overriding the entire friendlist object of yours.
Also, I hope you know what upsert does, if the update won't find the doc, then it will end up inserting one.

returning matching elements using MongoDB 4.0 find function

Mongodb returns non-matching elements in nested array
Here's my database sample:
const users = [{
'username':'jack',
'songs':[{
'song':'Another Love',
'likes':false
}, {
'song':"i'm into you",
'likes': true
}]
}, {
'username':'Stromae',
'songs':[{
'song':'Take me to church',
'likes':false
}, {
'song':"Habits",
'likes': true
}]
}];
I'm trying to find the following row:
const query = {'username':'Stromae' , 'songs.song':'Take me to church','songs.likes':true};
const result = await usersTable.find(query).project({'songs.$':1}).toArray();
as you see I'm trying to find a user who called "Stromae" and has a "Take me to church" song and he don't like it.
I'm expecting as result to be null, while the result is:
{ _id: 5d302809e734acbc5ffa2a8f,
songs: [ { song: 'Take me to church', likes: false } ] }
as you see from the result it ignores that I need "likes" field to be true.
As per my understanding you are trying to match data from 'songs' array which satisfying both the conditions for the 'song' and 'likes' both fields. But you haven't provided the logic like check both the fields for same array element. That's why it is checking this fields in whole 'songs' array.
To check condition for single array element you can use $elemMatch and for checking both the conditions are satisfying or not use the $and operator.
You can use your Mongo query as:
db.usersTable.find({
"username": "Stromae",
songs: {
$elemMatch: {
$and: [
{
"song": "Take me to church"
},
{
"likes": true
}
]
}
}
})
Just update your 'find' query, you might get your required result.

Mongoose findByIdAndUpdate() with select option [duplicate]

Using Mongoose in Nodejs you can return some fields using find.
eg.
User.findOne({_id:'132324'}, {first_name:1, last_name:1}).exec...
but I can't seem to figure out how to return certain fields using findOneAndUpdate.
User.findOneAndUpdate({_id:'132324'}, {$set : {..bla bla}}, {first_name:1, last_name:1}).exec....
Has anyone achieved this before?
I can't find it in the documentation.
From the manual, the options argument needs a "fields" key in it since there are other details such as "upsert" and "new" where this applies. In your case you also want the "new" option:
User.findOneAndUpdate(
{ "_id": "132324" },
{ "$set": { "hair_color": "yellow" } },
{
"fields": { "first_name":1, "last_name": 1 },
"new": true
}
).exec(...)
Alternately you may use .select()
User.select({ "first_name": 1, "last_name": 1 }).findOneAndUpdate(
{ "_id": "132324" },
{ "$set": { "hair_color": "yellow" } },
{ "new": true }
).exec(...)
Noting that without "new": true the document returned is in the state before the modification of the update was processed. Some times this is what you mean, but most of the time you really want the modified document.
It seems the syntax for findByIdAndUpdate has changed a little.
Its takes the form of Model.findByIdAndUpdate(query, update, options, (optional callback))
According to the docs, to specify which fields are returned you have to specify them in the options parameter. so, using the above example it would be:
User.findOneAndUpdate(
{id}, //query
{ $set: { "fieldToBeChanged": "update" } }, //update
{new:true, select: "fieldIWant anotherFieldIWant"}, //options
})
The new:true options is not necessary. If omitted mongoose defaults to returning the document before the updates were applied. Set to true and it will return the document after the updates have been made.
We can exclude any field while using mongoose update function findByIdAndUpdate with the help of select function,please have a look at the following code it will exclude password and __v from the Update response
User.findByIdAndUpdate({ _id: req.userData.UserId },req.body,{new: true}).select({Password: 0, __v: 0 })
.exec()
.then(result => {})
Try this:
User.findOneAndUpdate({_id:'132324'}, {update: '1235'}, {new: true}).select({ _id: 0 })
The select() will exclude the _id field from the result.
For MongoDb version 3.2+
User.findOneAndUpdate(
{ "_id": "132324" },
{ "$set": { "hair_color": "yellow" } },
{
"projected": { "first_name":1, "last_name": 1 },
"returnNewDocument": true
}
)...
For MongoDB version: 4.0.2, mongoose version: 5.13.7:
userModel.findOneAndUpdate({_id:'132324'},{$set:
{"first_name":"user","last_name":"one"}},
{new:true,select:{first_name:1, last_name:1}},(err,data)=>{}
Use option {new: true} in findOneAndUpdate (default: false)

mongodb remove document if array count zero after $pull in a single query

I have a requirement where my comments schema looks like the following
{
"_id": 1,
"comments": [
{ "userId": "123", "comment": "nice" },
{ "userId": "124", "comment": "super"}
]
}
I would like to pull the elements based on the userId field.
I am doing the following query
comments.update({},{$pull:{comments:{userId:"123"}}})
My requirement is that if the array length became zero after the pull operator I need to remove the entire document for some reason.Is there a away to do this in a single query?
PS:I am using the mongodb driver.Not the mongoose
If I'm reading your question right, after the $pull, if the comments array is empty (zero length), then remove the document ({ _id: '', comments: [] }).
This should remove all documents where the comments array exists and is empty:
comments.remove({ comments: { $exists: true, $size: 0 } })
I had a similar requirement and used this (using mongoose though):
await Attributes.update({}, { $pull: { values: { id: { $in: valueIds } } } }, { multi: true })
await Attributes.remove({ values: { $exists: true, $size: 0 } })
Not sure if it's possible to do this in one operation or not.
You can use middlewares for this.
http://mongoosejs.com/docs/middleware.html
Write a pre/post update method in mongodb to check your condition.

How to keep an array member count

I'm using nodeJS + Express + Mongoose + mongoDB
Here's my mongoDB User Schema:
{
friends: [ObjectId]
friends_count: Number
}
Whenever user adds a friend, a friendId will be pushed into friends array, and friends_count will be increased by 1.
Maybe there are a lot of actions will change the friends array, and maybe I will forgot to increase the friends_count. So I want to make sure that friends_count always equal to friends.length
Is there a good way or framework to make sure all of that?
P.S
I know how to update friends_count. What I mean is what if I forgot to?
Is there a way to automatically keep these two attributes sync?
Use the $ne operator as a "query" argument to .update() and the $inc operator to apply when that "friend" did not exist within the array as you $push the new member:
User.update(
{ "_id": docId, "friends": { "$ne": friendId } },
{
"$push": { "friends": friendId },
"$inc": { "friends_count": 1 }
},
function(err,numberAffected) {
}
)
Or to "remove" a friend from the list, do the reverse case with $pull:
User.update(
{ "_id": docId, "friends": friendId },
{
"$pull": { "friends": friendId },
"$inc": { "friends_count": -1 }
},
function(err,numberAffected) {
}
)
That way your friends_count stays in sync with the number of array elements present.
All you need to do is to update friends_count in both add and remove functions. For example:
User.findById(userId, function (err, user) {
if (user) {
user.friends.push(friendId);
user.friends_count++;
user.save();
}
});
FYI, I don't think it is necessary to add friends_count while you can get total numbers of friends by friends.length.

Resources