$elemMatch and update - mongodb

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.

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

$push into Array in Object in the document Mongoose

How do I $push into the Array which is in the Object in the document in mongoose?
The schema looks like this
{
rating: {
usersRated: Array,
rating: Number
}
}
I have tried {rating: {$push: {usersRated: data.userId}}}, but it does not work.
You should update the collection.
In your case:
model.update({ _id: id }, { $push: { 'rating.usersRated': data.userId }}, callback);
On update, you should pass the operator before the fields.

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

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

Mongodb - aggregation of subdocument and update with the result

I have the following problem. I have found and summarized each value in a subdocument.
It gives the following [ { _id: 551fb140e4b04589d8997213, sumOfpeople: 342 } ]
I want to take the sumOfpeople and insert it to the same House( the same req.params.house_id)
House.aggregate([
{ $match: {
id: req.params.house_id
}},
{ $unwind: '$people' }, // unwind creates a doc for every array element
{ $group: {
_id: '$_id',
sumOfpeople: { $sum: '$people.nr'}
}}
], function (err, result) {
if (err) {
console.log(err);
return;
}
console.log(result);
});
This is the model that I want insert the result after the aggregation into.
module.exports = mongoose.model('House', {
id: String,
people: [{
id: String,
nr: Number
}],
sumOfpeople: Number //this is the field that I want to update after the aggregation
});
I have tried to use $set : {sumOfpeople: { $sum: '$people.nr'}}.
Is it possible to use $set inside an aggregation, or how can it be solved otherwise?
There's no way in MongoDB to write results directly into an existing document while doing an aggregation.
You've got 2 options:
retrieve the results in your application code, and then in a second query update the document.
use the $out operator, that will write the results of the aggregation into a new collection. This operation will delete all documents in the results collection and insert the new one. ( http://docs.mongodb.org/manual/reference/operator/aggregation/out/ )