1

Hello i have simple collection:

{
    _id: 1,
    books: [
         { bookId: 55, c: 5},
         { bookId: 66, c: 6},
         { bookId: 77, c: 7},
    ]
}

How i can add new field by calulate other field? here i add field “Z” to current found object in nested array by it calculate field “C”

updateOne(
{ 
  _id : 1, 
  'books.bookId' : 66 
} ,
{
  [
      {    $addFields: { "books.$.z" : { "$sum" : ["$books.$.c", 1]  } }    }
  ]
}

Expected result:

{
    _id: 1,
    books: [
         { bookId: 55, c: 5},
         { bookId: 66, c: 6, z:7},
         { bookId: 77, c: 7},
    ]
}

I think there is a short entry (possibly using new $getField ?!), I think mango is still able to combine ‘position operator $’ + (‘varible operator reference by prefix $’ or ‘combine with $getField’) how i try in my sample

1 Answer 1

3

Use the aggregation pipeline in the update method to leverage the operators $map, $mergeObjects and $cond to achieve the desired results:

.updateOne(
    // The query will find docs where *at least* one bookId in the
    // books array equals 66 -- but remember it does not pinpoint
    // the location in the array!  We will tackle that in the update
    // pipeline to follow...
    { _id: 1, 'books.bookId': 66 },
    [
        { $set: {
            books: {
                $map: {
                    input: '$books',
                    in: {
                        $mergeObjects: [
                            '$$this',
                            {
                                $cond: [
                                    { $eq: ['$$this.bookId', 66] }, // IF books.bookId == 66
                                    { z: { $sum: ['$$this.c', 1] } }, // THEN merge a new field 'z' with calced value
                                    null  // ELSE merge null (a noop)
                                ]
                            }
                        ]
                    }
                }
            }
        } }    
    ]
)
Sign up to request clarification or add additional context in comments.

5 Comments

there is more simple ? with position operator $ or ‘combine with $getField
Yes, it's that simple as there is no need to use the $ operator when you update with the aggregation pipeline, just leverage the above aggregation operators to do the update.
will wait for more options, simpler options, with more modern operators such as v5.0 $getfield or similar
chridam has provided the simplest, tightest solution. There is no "object.fldX = val" operation in agg language; you have to use $mergeObjects, in this case taking the whole input object ($$this) from the map loop and merging the little object {z: ...} into it. Update pipelines are also much more powerful and as your needs change or you have variations, you don't get blocked by the limitations of the $ operator paradigm (notably, only matching on the FIRST thing encountered)
@BuzzMoschetti Couldn’t have said it better, cheers for the edit too!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.