'MongoDB how to update an object property in nested array
I have the following structure in my MongoDb where I have a topic object inside of a topics array. Within the topic object, I have a messages array. What I am trying to do is find every matching record (in this case, 'John Doe') in the collection (let's call it Records), and update the username property. How can I do this?
topics: [
{
topicname : 'Medical Records',
prop: propdata,
messages: [
{
username: 'John Doe',
message: 'Hello'
}
]
}
]
This is what i've tried...
collection.updateOne({'topics.messages.username' : 'John Doe'}, {
'$set':
{
'topics.messages.username' : 'Johnathan Doe'
},
But this does not work. How can I update every property that matches 'John Doe' in my collection?
Solution 1:[1]
One way to do it is using $unwind, $map and $group again:
db.collection.aggregate([
{
$match: {"topics.messages.username": "John Doe"}
},
{
$unwind: "$topics"
},
{
$project: {
"topics.messages": {
$map: {
input: "$topics.messages",
as: "item",
in: {
$mergeObjects: [
"$$item",
{
"username": {
$cond: [{$eq: ["$$item.username", "John Doe"]},
"Johnathan Doe",
"$$item.username"
]
}
}
]
}
}
},
"topics.topicname": 1,
"topics.prop": 1
}
},
{
$group: {
_id: "$_id", topics: {$push: "$topics"}
}
},
{ $merge: { into : "collection" } }
])
As you can see on this playground example.
The $match steps brings all the relevant documents to edit, the $unwind splits the items inside the topics array to single documents, so it will be easier for us to work. The $project step with the $map does the actual replacement of the name and the $group undo the the $unwind. The last part is to update the collection using $merge.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
