0

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?

IGJ
  • 75
  • 1
  • 10
  • Does this answer your question? [MongoDB - Update an object in nested Array](https://stackoverflow.com/questions/34431435/mongodb-update-an-object-in-nested-array) – tbhaxor Apr 28 '22 at 20:38
  • Please check [`$[]`](https://www.mongodb.com/docs/manual/reference/operator/update/positional-filtered/) – tbhaxor Apr 28 '22 at 20:39
  • I tried that but it does not work. I get this errror: Cannot create field 'username' in element {messages: [ .... – IGJ Apr 28 '22 at 20:42

1 Answers1

0

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.

nimrod serok
  • 14,151
  • 2
  • 11
  • 33