Search code examples
pythonarraysmongodbpymongo

MongoDB: Update element in an array where the index of the element is saved in the document


I have the following document structure.

{
    _id: ...,
    unique_id: 1234,
    config_no: 1,
    configs: [
        {
            data: "qwertyuiop" // random string
        },
        {
            data: "asdfghjkl" // random string
        }
    ]
}

I want to update value of data from one of the configs. The index of the config that needs to be updated is available in the config_no key.

Is there any way to update the value without querying the document.

This is what I am currently doing

doc = db.collection.findOne({"unique_id": 1234})
config_no = doc.config_no
db.collection.updateOne(
    {"unique_id": 1234},
    {"$set": {"configs."+config_no+".data": "zxcvbnm"}} //"configs.1.data"
)

Following is something what i would like to achive.

db.collection.updateOne(
    {"unique_id": 1234},
    {"$set": {"configs.${config_no}.data": "zxcvbnm"}}
)

Solution

  • You can $unwind with includeArrayIndex option. Use the index to perform conditional update and $merge back into the collection.

    db.collection.aggregate([
      {
        $match: {
          unique_id: 1234
        }
      },
      {
        "$unwind": {
          path: "$configs",
          includeArrayIndex: "idx"
        }
      },
      {
        $set: {
          "configs.data": {
            "$cond": {
              "if": {
                $eq: [
                  "$config_no",
                  "$idx"
                ]
              },
              "then": "zxcvbnm",
              "else": "$configs.data"
            }
          }
        }
      },
      {
        $group: {
          _id: "$_id",
          config_no: {
            $first: "$config_no"
          },
          configs: {
            $push: "$configs"
          },
          unique_id: {
            $first: "$unique_id"
          }
        }
      },
      {
        "$merge": {
          "into": "collection",
          "on": "_id",
          "whenMatched": "merge"
        }
      }
    ])
    

    Mongo Playground