添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Is there any way to use $cond along with ($set, $inc, ...) operators in update? (MongoDB 4.2) I want to update a field in my document by $inc it with "myDataInt" if a condition comes true, otherwise keeps it as it is:

db.mycoll.update(
    {"_id" : "5e9e5da03da783817d231dc4"},
    {"$inc" : {
       "my_data_sum" : {
           "$cond" : [
                  "$ne" : ["snapshot_time", new_snapshot_time)]
               },myDataInt, 0]
    {upsert=True, multi=False}

However, this gives an error in pymongo:

raise WriteError(error.get("errmsg"), error.get("code"), error)
pymongo.errors.WriteError: The dollar ($) prefixed field '$cond' in 'my_data_sum.$cond' is not valid for storage.

Any idea to avoid using find() before update in this case?

Update:

If I use the approach that Joe has mentioned, an exception will be raised in PyMongo (v3.10.1) due to using 'list' as a parameter in update_many() instead of 'dict':

from pymongo import MongoClient
db = MongoClient()['mydb']
db.mycoll.update_many(
    {"_id" : "5e9e5da03da783817d231dc4"},
    [{"$set" : {
       "my_data_sum" : {
           "$sum": [
               "$my_data_sum",
               {"$cond" : [
                   {"$ne" : ["snapshot_time", new_snapshot_time]},
                   myDataInt, 
    upsert:true
That ends up with this error:

  File "/usr/local/lib64/python3.6/site-packages/pymongo/collection.py", line 1076, in update_many session=session),
  File "/usr/local/lib64/python3.6/site-packages/pymongo/collection.py", line 856, in _update_retryable _update, session)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/mongo_client.py", line 1491, in _retryable_write return self._retry_with_session(retryable, func, s, None)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/mongo_client.py", line 1384, in _retry_with_session return func(session, sock_info, retryable)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/collection.py", line 852, in _update retryable_write=retryable_write)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/collection.py", line 823, in _update _check_write_command_response(result)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/helpers.py", line 221, in _check_write_command_response _raise_last_write_error(write_errors)
  File "/usr/local/lib64/python3.6/site-packages/pymongo/helpers.py", line 203, in _raise_last_write_error raise WriteError(error.get("errmsg"), error.get("code"), error)
pymongo.errors.WriteError: Modifiers operate on fields but we found type array instead. For example: {$mod: {<field>: ...}} not {$set: [ { $set: { my_data_sum: { $sum: [ "$my_data_sum", { $cond: [ { $ne: [ "$snapshot_time", 1586910283 ] }, 1073741824, 0 ] } ] } } } ]}

If you are using MongoDB 4.2, you can use aggregation operators with updates. $inc is not an aggregation operator, but $sum is. To specify a pipeline, pass an array as the second argument to update:

db.coll.update(
    {"_id" : "5e9e5da03da783817d231dc4"},
    [{"$set" : {
       "my_data_sum" : {
           "$sum": [
               "$my_data_sum",
               {"$cond" : [
                   {"$ne" : ["snapshot_time", new_snapshot_time]},
                   myDataInt, 
    {upsert:true, multi:false}
                I was trying to do the same approach but looks like pymongo do not accept "list" as the second argument for both "update" and "update_many". It only accepts dict type! Any idea? (using pymongo 3.10)
– Mishooq
                Apr 21, 2020 at 20:09
                According to the docs update_one and update_many accept a pipeline starting with version 3.9.  What version of MongoDB are you running?
– Joe
                Apr 21, 2020 at 22:18
                I'm running MongoDB 4.2 and PyMongo 3.10.1. I can run this Update in MongoDB with no problem. But PyMongo does not accept list type as the update_one or update_many parameters and gives this error: TypeError: document must be an instance of dict, bson.son.SON, or any other type that inherits from collections.Mapping
– Mishooq
                Apr 21, 2020 at 22:35

After spending some time and searching online, I figured that the update_many(), update_one(), and update() methods of Collection object in PyMongo do not accept type list as parameters to support the new Aggregation Pipeline feature of the Update operation in MongoDB 4.2+. (At least this option is not available in PyMongo v3.10 yet.)

However, looks like I could use the command method of the Database object in PyMongo which is an instance of the (MongoDB runCommand) and it worked just fine for me:

from pymongo import MongoClient
db = MongoClient()['mydb']
result = db.command(
        "update" : "mycoll",
        "updates" : [{
            "q" : {"_id" : "5e9e5da03da783817d231dc4"},
            "u" : [
                {"$set" : {
                   "my_data_sum" : {
                       "$sum": [
                           "$my_data_sum",
                           {"$cond" : [
                               {"$ne" : ["snapshot_time", new_snapshot_time]},
                               myDataInt,
            "upsert" : True,
            "multi" : True
        "ordered": False

The command method of the database object gets a dict object of all the required commands as its first argument, and then the list of Aggregation Pipeline can be included inside the dict object (q is the update query, and the u defined the fields to be updated).

result is a dictionary of Ack message from MongoDB which contains 'nModified', 'upserted', and 'writeErrors'.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.