'MongoDB using $cond with Update ($inc)

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, 
                   0
               ]}
           ]
       }
    }}],

    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 ] } ] } } } ]}


Solution 1:[1]

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, 
                   0
               ]}
           ]
       }
    }}],
    {upsert:true, multi:false}
)

Solution 2:[2]

https://mongoplayground.net/p/1AklFKuhFi6

[
  {
    "id": 1,
    "like": 3
  },
  {
    "id": 2,
    "like": 1
  }
]

let value = 1,

if you want to increment then use

value = -1 * value

db.collection.aggregate([
  {
    "$match": {
      "id": 1
    }
  },
  {
    "$set": {
      "count": {
        $cond: {
          if: {
            $gt: [
              "$like",
              0
            ]
          },
          then: {
            "$subtract": [
              "$like",
               value
            ]
          },
          else: 0
        }
      }
    }
  }
])

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Joe
Solution 2