Search code examples
mongodbaggregate

MongoDB: add element to an array with an object that contains field calculated on another field


I have this document:

{
    "_id" : ObjectId("626c0440e1b4f9bb5568f542"),
    "bc" : [ 
        {
            "bc_id" : ObjectId("000000000000000000000003"),
            "price" : 102
        }
    ],
    "stock_price" : 50
}

I need to add an element to bc array that has as price a value calculated from the stock_price. I tried something like this:

db.collection.updateMany(
    {_id:ObjectId("626c0440e1b4f9bb5568f542")},
    [
        {$addToSet: {bc: {bc_id:ObjectId("000000000000000000000004"), price:{$multiply:[{$toDouble:"$stock_price"},0.80]}}}}
    ]
)

but $addToSet is not valid in aggregation pipeline. The expected result is:

{
    "_id" : ObjectId("626c0440e1b4f9bb5568f542"),
    "bc" : [ 
        {
            "bc_id" : ObjectId("000000000000000000000003"),
            "price" : 102
        },
        {
            "bc_id" : ObjectId("000000000000000000000004"),
            "price" : 40
        }
    ],
    "stock_price" : 50
}

Solution

  • Query

    • you can use an pipeline update to refer to the stock_price field
    • find by _id
    • if "$bc.bc_id" array contains the new bc_id(here newid=3) do nothing keep old bc, else push in the end (concat arrays)

    Playmongo

    update(
    {"_id": {"$eq": ObjectId("626c0440e1b4f9bb5568f542")}},
    [{"$set": 
       {"bc": 
         {"$cond": 
           [{"$in": [3, "$bc.bc_id"]}, "$bc",
             {"$concatArrays": 
               ["$bc",
                 [{"bc_id": 3, "price": {"$multiply":["$stock_price", 0.8]}}]]}]}}}],
    {"multi": true})