Search code examples
arraysmongodbaggregationmongodb-updatefindoneandupdate

How to update an array value in mongodb using aggregation


My Document looks something like this

{ _id: ObjectId("60b114b2415731001943b17f"),
processList:[ 
    { processName: 'Wood cutting',
    createdAt: '2021-05-28T08:59:06.260Z',
    updatedAt: '2021-05-28T08:59:06.260Z',
    id: '60b0f0e9659a3b001c235300',
    endTime: '2021-07-09T22:25:57.973Z',
    isCompleted: false },
    { processName: 'Painting',
    createdAt: '2021-05-28T13:32:02.441Z',
    updatedAt: '2021-05-28T13:32:02.441Z',
    id: '60b0f0e9659a3b001c235301',
    endTime: 2021-05-28T17:05:06.067Z,
    isCompleted: true },
    {processName: 'Varnishing',
    createdAt: '2021-05-28T09:46:33.169Z',
    updatedAt: '2021-05-28T09:46:33.169Z',
    id: '60b0f0e9659a3b001c235302',
    endTime: 2021-05-28T20:05:06.067Z,
    isCompleted: false } 
],

   companyId: '60b0a2b7b0beab001a068f8c',
   customerId: '60b11289415731001943b17d',
   productName: 'Queen size bed',
   quantity: 1,
   orderStartedTime: 2021-05-28T16:05:06.067Z,
   estimatedEndTime: 2021-05-29T01:05:06.067Z,
   createdAt: 2021-05-28T16:05:06.069Z,
   updatedAt: 2021-07-09T22:20:58.019Z,
   __v: 0,
  percentageCompleted: 33.33333333333333 }

I'm trying to update the percentageCompleted and one of the process list's isCompleted true based on the id inside processList.

I ran this query but throws error

db.orders.findOneAndUpdate(
{
 _id: ObjectId('60b114b2415731001943b17f')
},
[
    {
    
    $set: {"processList.$[element].isCompleted": true} 
},
{
        multi: true,
        arrayFilters: [{ 'element.id': { $eq: "60b0f0e9659a3b001c235300" } }],
},


{
    $set: {
        percentageCompleted: {
            $multiply: [
                {
                    $divide: [{
                        $size: {
                            $filter: {
                                input: "$processList",
                                as: "process",
                                cond: { $eq: ["$$process.isCompleted", true] }
                            }
                        }
                    },
                    { $size: "$processList" }]
                }, 100
            ]
        },
    }
}
]
)

When I exclude the updation of array (isCompleted), the updation of percentageCompleted is getting calculated and set. Can someone help me how to proceed. Thanks in advance.


Solution

  • We can mix update operators with aggregate operators, if we need aggregate operators we do update it with pipeline update.

    pipeline updates require MongoDB >=4.2

    Query

    • map to update the processList
    • your $set from your query

    Test code here

    db.collection.update({
      "_id": "60b114b2415731001943b17f"
    },
    [
      {
        "$set": {
          "processList": {
            "$map": {
              "input": "$processList",
              "in": {
                "$cond": [
                  {
                    "$eq": [
                      "$$this.id",
                      "60b0f0e9659a3b001c235300"
                    ]
                  },
                  {
                    "$mergeObjects": [
                      "$$this",
                      {
                        "isCompleted": true
                      }
                    ]
                  },
                  "$$this"
                ]
              }
            }
          }
        }
      },
      {
        "$set": {
          "percentageCompleted": {
            "$multiply": [
              {
                "$divide": [
                  {
                    "$size": {
                      "$filter": {
                        "input": "$processList",
                        "as": "process",
                        "cond": {
                          "$eq": [
                            "$$process.isCompleted",
                            true
                          ]
                        }
                      }
                    }
                  },
                  {
                    "$size": "$processList"
                  }
                ]
              },
              100
            ]
          }
        }
      }
    ])