【问题标题】:MongoDB using $cond with Update ($inc)MongoDB 使用带有更新的 $cond ($inc)
【发布时间】:2020-04-21 16:28:45
【问题描述】:

有没有办法在更新中使用 $cond 和 ($set, $inc, ...) 运算符? (MongoDB 4.2) 如果条件满足,我想通过 $inc 用“myDataInt”更新我的文档中的一个字段,否则保持原样:

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

但是,这会在 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.

在这种情况下,有什么想法可以避免在更新之前使用 find() 吗?


更新:

如果我使用 Joe 提到的方法,由于在 update_many() 中使用 'list' 而不是 'dict' 作为参数,PyMongo (v3.10.1) 会引发异常:

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
)


最终出现此错误:

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

【问题讨论】:

  • 请在您的帖子中添加示例输入文档。

标签: python mongodb pymongo mongodb-update


【解决方案1】:

如果您使用的是 MongoDB 4.2,则可以将聚合运算符与更新一起使用。 $inc 不是聚合运算符,但 $sum 是。要指定管道,请将数组作为第二个参数传递给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}
)

【讨论】:

  • 我试图做同样的方法,但看起来 pymongo 不接受“list”作为“update”和“update_many”的第二个参数。它只接受 dict 类型!任何的想法? (使用 pymongo 3.10)
  • 根据 docs update_oneupdate_many 接受从 3.9 版本开始的管道。您运行的是哪个版本的 MongoDB?
  • 我正在运行 MongoDB 4.2 和 PyMongo 3.10.1。我可以毫无问题地在 MongoDB 中运行此更新。但是 PyMongo 不接受列表类型作为 update_one 或 update_many 参数并给出此错误:TypeError: document must be an instance of dict, bson.son.SON, or any other type that inherits from collections.Mapping
  • 您能否将新的python代码编辑到问题中以便我们尝试一下?
【解决方案2】:

经过一段时间的网上搜索,我发现 PyMongo 中 Collection 对象的 update_many()update_one()update() 方法不接受类型列表作为参数,以支持更新的新聚合管道功能MongoDB 4.2+ 中的操作。 (至少这个选项在 PyMongo v3.10 中还没有。)

但是,看起来我可以在 PyMongo 中使用 Database 对象的 command 方法,它是 (MongoDB runCommand) 的一个实例,它对我来说效果很好:

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,
                               0
                           ]}
                       ]
                   }
                }}
            ],
            "upsert" : True,
            "multi" : True
        }],
        "ordered": False
    }
)

数据库对象的command方法获取所有需要命令的dict对象作为它的第一个参数,然后可以将聚合管道列表包含在dict对象中(q是更新查询,而u 定义了要更新的字段)。

result 是来自 MongoDB 的 Ack 消息字典,其中包含 'nModified''upserted''writeErrors'

【讨论】:

    【解决方案3】:

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

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

    设值 = 1,

    如果你想增加然后使用

    值 = -1 * 值

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

    【讨论】:

      猜你喜欢
      • 2015-11-10
      • 1970-01-01
      • 2021-10-16
      • 1970-01-01
      • 1970-01-01
      • 2016-09-22
      • 2021-08-04
      • 2019-03-16
      • 1970-01-01
      相关资源
      最近更新 更多