Search code examples
mongodbmongoose

positional "$" not updating correct value in array, instead creating new?


I need to $inc qty in 2 arrays and then return updated document.

Mongodb Document

     _id: _id ***********
     quantity: [
      {
        "storage": "GODOWN",
        "qty": 1,
        "_id": "666e0f15876d5be1a8ce0a04"
      },
      {
        "storage": "SHOP",
        "qty": 0,
        "_id": "666e0f15876d5be1a8ce0a05"
      },
      {
        "storage": "GODOWN 2",
        "qty": 0,
        "_id": "666e0f15876d5be1a8ce0a06"
      }
    ],
     pricing: [{
        "firstAddedDate": "06/16/2024",
        "mrp": 0,
        "price": 0,
        "qty": 1,
        "total": 80,
        "default": true,
        "_id": "666e0f15876d5be1a8ce0a03"
      }]

I need to increment the qty of pricing array's object that have value of 'default: true. Here is the code -

defualtPricingUpdated = await Item.findOneAndUpdate(
     { _id: newEntry.itemID, "pricing.default": true, "quantity._id": newEntry.storageID },
     { $inc: { "pricing.$.qty": Number(newEntry.qty), "quantity.$.qty": newEntry.qty, "pricing.$.total": newEntry.amount }},
     { returnDocument: "after" }
     ).session(session)

For reason this command is creating a new entry in pricing Array instead of incrementing the existing one.


Solution

  • From the findings, when the matching quantity object position is greater than 1, it will add a new object to the pricing array.

    Hence, work with $[<identifier>] filtered positional operator will be more accurate.

    defualtPricingUpdated = await Item.findOneAndUpdate({
      _id: newEntry.itemID,
      "pricing.default": true,
      "quantity._id": newEntry.storageID
      
    },
    {
      $inc: {
        "pricing.$[p].qty": NumberInt(newEntry.qty),
        "quantity.$[q].qty": newEntry.qty,
        "pricing.$[p].total": newEntry.amount
      }
    },
    {
      arrayFilters: [
        {
          "p.default": true
        },
        {
          "q._id": newEntry.storageID  
        }
      ],
      returnDocument: "after"
    }).session(session)
    

    Demo @ Mongo Playground