$push 和 $set 在同一个更新查询中,条件为 $cond pymongo mongodb

Posted

技术标签:

【中文标题】$push 和 $set 在同一个更新查询中,条件为 $cond pymongo mongodb【英文标题】:$push and $set in same update query with condition $cond pymongo mongodb 【发布时间】:2020-08-23 15:20:19 【问题描述】:

我正在尝试更新我的收藏

对于单,对象需要更新状态和更新时间。

输入对象ID为id新状态为当前status

条件如果new status与DB中的status不同,则需要将$pushnew statustimestamp放入activity_log数组中。 并更新更新记录的updated_timestatus

如果new status 和之前的状态相同,那么updated_time 将被更新。

是否可以在 pymongo 中使用单次更新来做到这一点?

collection.update(
        '_id': ObjectId(id),
    , 
        '$cond': 
            'if': 
                'status': 
                    '$ne': current_status
                
            ,
            'then': 
                '$push': 
                    'activity_log': 
                        'status': current_status,
                        'changed_time': datetime.now()
                    
                
            ,
            'else': None
        ,
        '$set': 
            'status': current_status,
            'updated_time': datetime.now()
        
    )

【问题讨论】:

请使用 1) 示例文档、2) 输入、3) 要应用的条件和 4) 应用更新后的结果文档来编辑此问题!数据库版本? 更新了输入和条件mongodb版本为MongoDB 4.2.5 Community 我已经更新了我的答案,可以在单个查询中完成,我已经在 Mongo 客户端上尝试过更新的查询正在运行,请检查。 【参考方案1】:

您可以在单个查询中执行此操作,从 MongoDB 4.2 更新查询支持aggregation pipeline,您可以按照以下代码执行此操作

collection.update(
     '_id': ObjectId(id), 
     ['$set': 
            'status': current_status,
            'updated_time': datetime.now(),
            'activity_log':
              '$cond': 
                'if': '$ne': ['$status',current_status],
                'then': $concatArrays:['$activity_log',[
                          
                           'status': current_status,
                           'changed_time': datetime.now()
                          
                ]],
                'else': '$activity_log'
            
      ]
)

【讨论】:

【参考方案2】:

$cond 运算符不是像 if-then-else 那样的流控制,它是一个返回值的表达式。

如果要根据同一文档中另一个字段的值有条件地更新一个字段,可以使用更新的管道形式,将$cond表达式的结果分配给该字段。

collection.update(
     '_id': ObjectId(id), 
     ['$set': 
            'status': current_status,
            'updated_time': datetime.now(),
            'activity_log':
              '$cond': 
                'if': '$ne': ['$status',current_status]
                'then': $concatArrays:['$activity_log',[
                          
                           'status': current_status,
                           'changed_time': datetime.now()
                          
                ]],
                'else': '$activity_log'
            
      ]
)

【讨论】:

我认为上面的方式是正确的pymongo正在触发in validate_is_mapping raise TypeError("%s must be an instance of dict, bson.son.SON, or " TypeError: document must be an instance of dict, bson.son.SON, or any other type that inherits from collections.Mapping MongoDB 4.2 中添加的管道更新形式。如果您使用的 pymongo 版本不支持 update 函数,您可以使用 db.command 运行 update 数据库命令

以上是关于$push 和 $set 在同一个更新查询中,条件为 $cond pymongo mongodb的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis动态SQL

使用 scala 在 Jooq 中进行交易和条件更新

update set语句

使用$ set / $ push更新子文档数组的许多子项

mongodb_修改器($inc/$set/$unset/$push/$pop/upsert......)

mongodb_修改器($inc/$set/$unset/$push/$pop/upsert......)