How to get _id of inserted object in mongodb mongoose with addToSet - mongodb

Using addToSet with mongoose, how do I get back the newly inserted id of the object. In this example the _id of the friend added to the friends collection. Friend is defined in the model as having an _id field.
db.user.update(
{ _id: 1 },
{ $addToSet: { friends: {name:"bob"} } }
)

addToSet() will adds an object to an array. So if I understand your question correctly, this might work:
db.user.update(
{ _id: 1 },
{ $addToSet: { friends: {name:"bob"} } },
{ new: true}
).exec( (err, user) => {
user.friends // an array
var bob = user.friends.filter( x => x.name == "bob");
bob._id
})

Related

How to increment filed in mongodb mongoose

const options = {
$addToSet: { whoLikes: userId },
$inc: { likesCount: 1 },
new: true,
};
collection.findByIdAndUpdate({ _id: postId }, options)
What I want is increment likesCount only if whoLikes array length is get incremented.
Right now likesCount incrementing all the time doesn't matter how many objects inside whoLikes array.
I'm using mongoose, node.js
use findOneAndUpdate() method
Just check condition in your query part whoLikes: { $ne: userId } userId should not inside whoLikes array
user $push instead of $addToSet
other options should be in third parameter new:true
const options = {
$push: { whoLikes: userId },
$inc: { likesCount: 1 }
};
collection.findOneAndUpdate(
{
_id: postId,
whoLikes: { $ne: userId }
},
options,
{ new: true }
)
Ex1: Add UserID that is not present
Playground
Ex2: Add UserID that is already present
Playground

Update a document and upsert a subdocument in a single query

How do I update an item in the parent document and upsert a subdocument in a single query?
This is my example schema.
const ExampleSchema = new Schema({
user_count: {
type: String,
default: 0
},
users: [
{
id: {
type: Schema.Types.ObjectId,
ref: "users",
unique: true
},
action: {
type: Boolean
}
}
],
});
I am trying to add +1 to user_count and upsert a document to the users array in a single query.
const result = await Example.updateOne(
{
_id: id,
},
{
$set: {
"user_count": user_count++,
"users.$.id": req.user.id,
"users.$.action": true
}
},
{ upsert: true }
);
I have tried the above code, but got the following error.
[0] 'The positional operator did not find the match needed from the query.',
[0] [Symbol(mongoErrorContextSymbol)]: {} }
I'm not familiar with mongoose, so I will take for granted that "user_count": user_count++ works.
For the rest, there are two things that won't work:
the $ operator in "users.$.id": req.user.id, is known as the positional operator, and that's not what you want, it's used to update a specific element in an array. Further reading here: https://docs.mongodb.com/manual/reference/operator/update/positional/
the upsert is about inserting a full document if the update does not match anything in the collection. In your case you just want to push an element in the array right?
In this case I guess something like this might work:
const result = await Example.updateOne(
{
_id: id,
},
{
$set: {
"user_count": user_count++
},
$addToSet: {
"users": {
"id": req.user.id,
"action": true
}
}
}
);
Please note that $push might also do the trick instead of $addToSet. But $addToSet takes care of keeping stuff unique in your array.
db.collection.findOneAndUpdate({_id: id}, {$set: {"user_count": user_count++},$addToSet: {"users": {"id": req.user.id,"action": true}}}, {returnOriginal:false}, (err, doc) => {
if (err) {
console.log("Something wrong when updating data!");
}
console.log(doc);
});

MongoDb remove element from array as sub property

I am trying to remove an entry in an array that is a sub property of a document field.
The data for a document looks like this:
{
_id: 'user1',
feature: {
enabled: true,
history: [
{
_id: 'abc123'
...
}
]
},
...
}
For some reason I have not been able to remove the element using $pull and I'm not sure what is wrong.
I've looked at the official docs for $pull, this well-known answer, as well this one and another.
I have tried the following query
db.getCollection('userData').update({ _id:'user1' }, {
$pull: {
'feature.history': { _id: 'abc123' }
}
})
and it has no effect. I've double-checked _id and it is a proper match. I've also tried filtering based on the same entry, thinking I need to target the data I'm trying to remove:
db.getCollection('userData')
.update({ _id: 'user1', 'feature.history': { _id: 'abc123' }, { ... })
So far no luck
You need to cast your id to mongoose ObjectId
db.getCollection('userData').update(
{ "_id": "user1" },
{ "$pull": { "feature.history": { "_id": mongoose.Types.ObjectId(your_id) } }
})
db.getCollection('userData').update({ _id:'user1', "feature.history._id" : "abc123" }, {
$pull: {
'feature.history.$._id': 'abc123'
}
})

MongoDB – Find all docs by array of ids within an array of objects

I want to find any entries in my collection 'groups' where the id of the object in the array 'games' is in an array of ids.
The logic in JS:
for (const game in games) {
return game.find(field => field.id.indexOf(arrayOfIds));
}
And my idea of logic for mongoose:
db.groups.find({ "games.id": { $in: ["5a945...", "1701fa..."] } });
you should use $elemMatch to match the array
db.collection.find({
"games": {
$elemMatch: {
id: {
$in: ["5a945...", "1701fa..."]
}
}
}
})
https://mongoplayground.net/p/cmphODhmGJg

$elemMatch and update

I would like to update a subdocument that was fetched using $elemMatch. I've found some posts online but so far I am not able to get it to work. This is what I have:
Schema:
var user = {
_id: ObjectId
addresses: [{
_id: ObjectId
street: String
}]
};
Code:
this.findOne({
'addresses._id': address_id
}, { 'occurrences': { $elemMatch: {
'_id': address_id
}}})
.exec(function(err, doc) {
if (doc) {
// Update the sub doc
doc.addresses[0].street = 'Blah';
doc.update({ 'addresses': { $elemMatch: { '_id': address_id }}}, { $set: {"addresses.$.street": doc.addresses[0].street }})
.exec(function(err, count) {
...
The above results in the address sub doc to be wiped out and a blank new one recreated. How can I save the doc/subdoc?
My goal is to be able to fetch a document (user) by subdocument (addresses) ID, modify that one matching address then save it.
You can do this all with a single update call on the model instead of fetching it first with findOne:
User.update(
{'addresses._id': address_id},
{$set: {'addresses.$.street': 'Blah'}},
function(err, count) { ... });
This uses the positional $ operator in the $set to target just the addresses element that was matched in the query.