15

我有一个文件

{ key : 'key1', value : 'value1', update_time : 100 }

我只想用最近(更大)的更新时间来改变。我现在正在做的是:

def update_key1(new_value, new_time):
    record = find_one( { key : 'key1' } )
    if not record or record['update_time'] < new_time:
        update( { key : 'key1', value : new_value, update_time : new_time }, upsert=True)

显然这是到数据库的额外往返,但更重要的是文档上没有锁定,并发调用可能导致数据库中剩余的 new_time 值较低。有没有办法仅在条件为真时执行 upsert?

编辑:只是为了澄清,目的不是为每个键创建多个文档,然后对查找进行排序。虽然这可以解决我的问题,但这些值会发生很大变化并且会浪费很多空间。

4

5 回答 5

2

由于无法以原子方式完成整个事情,有两种现有条件需要您进行更改,您可以以原子方式处理每一种情况:

  • 不存在密钥的记录
  • 密钥的记录存在且其update_time早于new_time

更新密钥的现有记录:

def update_if_stale(key, new_value, new_time):
    collection.update({'key': key,
                       'update_time': {'$lt': new_time}
                       },
                      {'$set': {'value': new_value,
                                'update_time': new_time
                                }
                       }
                      )

如果之前不存在 key 的记录,则插入:

def insert_if_missing(key, new_value, new_time):
    collection.update({'key': key},
                      {'$setOnInsert': {'value': new_value,
                                        'update_time': new_time
                                        }
                       },
                      upsert=True
                      )

$setOnInsert在 MongoDB 2.4 中添加)

您也许可以将这些放在一起以获得您需要的东西,例如:

def update_key(key, new_value, new_time):
    insert_if_missing(key, new_value, new_time)        
    update_if_stale(key, new_value, new_time)

但是,根据系统中可能的删除/插入时间尺度,您可能需要多次调用(更新/插入/更新)或其他恶作剧。

另外:如果您希望将缺少该update_time字段的记录视为过时记录进行更新,请更改{'$lt': new_time}}{'$not': {'$gte': new_time}}

于 2013-10-06T23:01:20.463 回答
2

如果您在 , 上添加唯一约束key,则updateOne使用update_time过滤器upsert=True并将

  1. 插入缺失的记录
  2. 更新陈旧的记录
  3. 尝试使用 stale input 更新时抛出错误(因为更新将不匹配过滤条件,并且插入会因约束而失败)
collection.updateOne({'key': key,
                      'update_time': {'$lt': new_time}
                      },
                     {'$set': {'value': new_value,
                               'update_time': new_time
                               }
                      },
                     upsert=True
                     )

您可以捕获错误并检查code: 11000(违反唯一约束)以专门处理那些尝试更新到过去状态的情况。

于 2020-10-15T16:57:02.930 回答
1

如果 WPCoder 对 upsert=True 的响应不是您想要的,那么您可能需要 $setOnInsert,它尚未实现:https ://jira.mongodb.org/browse/SERVER-340 。它应该在 2.4.0 中实现。

于 2012-12-07T19:50:20.787 回答
0

似乎您正在寻找findAndModify。对不起,我不熟悉 python,所以我不能给你一个代码片段,但命令应该很简单。

于 2012-12-07T15:34:31.947 回答
0

您可以进行有条件的更新:

db.MyObjects.update( { key : "key1", value: { $lt : aValue }},
                    { $set : { value : aValue }});
于 2012-12-07T19:13:59.037 回答