2

I have a schema like this

{
    "_id": "5f86da4b5bb9a62742371409",
    "status" : true,
    "doc": [
      {
        "_id": "5f86cacbe4d7c423f21faf50",
        "a": 4,
        "b": null
      },
      {
        "_id": "5f86cb01a1ca5124063299c1",
        "a": 6,
        "b": null

      }
    ]
}

And I have an update in the form of


[
      {
        "_id": "5f86cacbe4d7c423f21faf50",
        "b": 90
      },
      {
        "_id": "5f86cb01a1ca5124063299c1",
        "b": 45

      }
    ]

How can I update the collection to end up like this?

{
    "_id": "5f86da4b5bb9a62742371409",
    "status" : true,
    "doc": [
      {
        "_id": "5f86cacbe4d7c423f21faf50",
        "a": 4,
        "b": 90
      },
      {
        "_id": "5f86cb01a1ca5124063299c1",
        "a": 6,
        "b": 45

      }
    ]
}

Basically I want to update the subdocument with specific keys only (leaving other keys intact)

niksmac
  • 2,667
  • 3
  • 34
  • 50

1 Answers1

1

You can use update with aggregation pipeline from MongoDB 4.2,

  • $map to iterate loop of array doc and inside it iterate through updateDocs array, it will return matching b, and then $mergeObjects will return updated document,
let updateDocs = [
  { "_id": mongoose.Types.ObjectId("5f86cacbe4d7c423f21faf50"), "b": 90 },
  { "_id": mongoose.Types.ObjectId("5f86cb01a1ca5124063299c1"), "b": 45 }
];

db.collection.updateMany({},
[
  {
    $set: {
      doc: {
        $map: {
          input: "$doc",
          as: "d",
          in: {
            $mergeObjects: [
              "$$d",
              {
                $reduce: {
                  input: updateDocs,
                  initialValue: {},
                  in: {
                    $cond: [
                      { $eq: ["$$this._id", "$$d._id"] },
                      { b: "$$this.b" },
                      "$$value"
                    ]
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
]
)

Playground

turivishal
  • 34,368
  • 7
  • 36
  • 59
  • Doesn't seems to be working in my actual dataset, but thanks anyway. It gave me some idea. https://ibb.co/S03yRmB – niksmac Oct 14 '20 at 13:05
  • You need to pass ObjectId, currently its string just wrap it `ObjectId("5f86cacbe4d7c423f21faf50")` and then try. – turivishal Oct 14 '20 at 13:46
  • 1
    btw, you are missing an array wrapper `[]` around your `$set` without it it won't update the database. – niksmac Oct 15 '20 at 03:57