Updates with Aggregation Pipeline

With mongo shell, I can do something like this:

db.collection.updateMany({},
[
    {
        $set: {
            new_field: {
                $avg: "$sources.value"
            }
        }
    }
])

When the data looks like this:

{
  _id: (ID),
  sources: [{value: 10, ...}, {value: 20, ...}]
}

The output is as expected, with the average being added to the document.

I am trying to reproduce this with PyMongo, to no avail.
When I try this: pymongo.UpdateOne({filter}, {'$set': {'new_field': {'$avg': "$sources.value"}}}), I get this error:

The dollar ($) prefixed field ‘$avg’ in ‘new_field.$avg’ is not valid for storage

When I try wrapping the whole $set dictionary in a string, it puts the whole string as the value instead of executing it.

Is there a proper way to have PyMongo use an aggregation during a set?

Note: For the sake of the post, I am trivializing the example. The real problem is a more complex way of calculating the average given different conditions, and the sources object is more than just a list of one value to take the average of.

Hello @Reid_Gahan, Welcome to MongoDB Community Forum,

Update part should be in array bracket because its aggregation pipeline, that you have used correctly in your mongo shell query but not in pymongo query, try,

pymongo.UpdateOne({filter}, [{'$set': {'new_field': {'$avg': "$sources.value"}}}])

I may have trivialized too much… that worked as desired, but I also need to do a $addToSet and $setOnInsert in the UpdateOne().

If I do:

Updateone({filter}, [{'$set': {}, '$addToSet': {}}])

It fails with error:

pymongo.errors.OperationFailure: A pipeline stage specification object must contain exactly one field

If I do:

Updateone({filter}, [{'$set': {}}, { '$addToSet': {}}])

It fails with error:

pymongo.errors.OperationFailure: Unrecognized pipeline stage name: ‘$addToSet’

For context:

UpdateOne({filter}, {'$set': {}, '$addToSet': {}, etc...})

worked prior to adding the aggregation steps to the $set step. Now if I try it in that format, I get aforementioned error about dollar prefixed field.

$addToSet is not aggregation pipeline stage, its update operator you can’t use this way in aggregation pipeline.

I would suggest to read below documents you will get idea, There are 2 ways to update documents,

1) Regular Update:

2) Update with aggregation pipeline:

1 Like

Great, thank you for the clarification there. This made sense, with the distinction between Update Document and Aggregation Pipeline. The usage of $set for both cases threw me off, so thank you for explaining.

For posterity sake, my solution is to do all the UpdateOnes for the collection, and then do an UpdateMany that will run the aggregation pipeline.