Search code examples
mongodbaggregation

How to update mongoDB document with condition of containing object field in the array of objects


The goal, is to lookup for object field value in user.inCart array, if the value is found, update the object field quntity. Else case push a new object to the array.

I have this code working fine:

       Users.findOneAndUpdate({
       id:req.user.id,
       'inCart.item': req.body.item
   },
   {
       $inc: {'inCart.$.quantity': req.body.quantity}
   }).then(data=>{
       if (data!=null) {
           res.status(200)
       } else{
           Users.findOneAndUpdate({
               id:req.user.id,
           },{
               $push : {inCart:{item:req.body.item, quantity: req.body.quantity} }
           }).then(()=>res.status(200))
       }
   })

}

is there a way to do the same with a single reqest?


Solution

  • Query

    • you can do it with pipeline update MongoDB >= 4.2
    • find the id
    • filter to see if item exists (in code replace the 1 with the item identifier (itemName/code etc))
    • if isNewItem => add it to the inCard with quantity 1
    • else $map and update the quantity by 1

    *instead of filter+map, you could do it with 1 reduce also, but concatArrays is slower if you had like inCard>1000 items

    Test code here

    update({"id":{"$eq":1}},
    [{"$set":
      {"isNewItem":
       {"$eq":
        [{"$filter":
          {"input":"$inCard", "cond":{"$eq":["$$this.item", 1]}}},
         []]}}},
     {"$set":
      {"inCard":
       {"$cond":
        ["$isNewItem",
         {"$concatArrays":["$inCard", [{"item":1, "quantinty":1}]]},
         {"$map":
          {"input":"$inCard",
           "in":
           {"$cond":
            [{"$eq":["$$this.item", 1]},
             {"$mergeObjects":
              ["$$this", {"quantity":{"$add":["$$this.quantity", 1]}}]},
             "$$this"]}}}]}}}, {"$unset":["isNewItem"]}])