gpt4 book ai didi

python - Pymongo replace_one modified_count 总是 1 即使没有改变任何东西

转载 作者:可可西里 更新时间:2023-11-01 09:12:56 34 4
gpt4 key购买 nike

为什么以及如何能这样工作?

item = db.test.find_one()
result = db.test.replace_one(item, item)
print(result.raw_result)
# Gives: {u'n': 1, u'nModified': 1, u'ok': 1, 'updatedExisting': True}
print(result.modified_count)
# Gives 1

当 mongodb shell 中的等价物总是 0

item = db.test.findOne()
db.test.replaceOne(item, item)
# Gives: {"acknowledged" : true, "matchedCount" : 1.0, "modifiedCount" : 0.0}

我如何才能获得一致的结果并正确检测到替换项何时真正更改了数据?

最佳答案

这是因为 MongoDB 以二进制 (BSON) 格式存储文档。 BSON 文档中的键值对可以有任何顺序(除了 _id 总是第一个)。让我们从 mongo shell 开始第一的。 mongo shell 在读取和写入数据时保留键顺序。例如:

> db.collection.insert({_id:1, a:2, b:3})
{ "_id" : 1, "a" : 2, "b" : 3 }

如果您正在执行 replaceOne()使用此文档值,它将避免修改,因为存在现有的 BSON。

> var doc = db.collection.findOne()
> db.collection.replaceOne(doc, doc)
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }

但是,如果您更改字段的顺序,它会检测到修改

> var doc_2 = {_id:1, b:3, a:2}
> db.collection.replaceOne(doc_2, doc_2)
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

让我们走进 Python 世界。 PyMongo默认将 BSON 文档表示为 Python 字典,未定义 Python 字典中键的顺序。因此,您无法预测它将如何序列化为 BSON。根据您的示例:

> doc = db.collection.find_one()
{u'_id': 1.0, u'a': 2.0, u'b': 3.0}

> result = db.collection.replace_one(doc, doc)
> result.raw_result
{u'n': 1, u'nModified': 1, u'ok': 1, 'updatedExisting': True}

如果它对您的用例很重要,一种解决方法是使用 bson.SON .例如:

> from bson import CodecOptions, SON
> opts=CodecOptions(document_class=SON)
> collection_son = db.collection.with_options(codec_options=opts)
> doc_2 = collection_son.find_one()
SON([(u'_id', 1.0), (u'a', 2.0), (u'b', 3.0)])

> result = collection_son.replace_one(doc_2, doc_2)
{u'n': 1, u'nModified': 0, u'ok': 1, 'updatedExisting': True}

您还可以观察到 bson.SON 在 PyMongo (v3.3.0) 中使用,即 _update() method .另见相关文章:PyMongo and Key Order in SubDocuments .

更新以回答另一个问题:

据我所知,没有将嵌套字典转换为 SON 的“标准”函数。尽管您可以自己编写自定义 dictSON 转换器,例如:

def to_son(value):
for k, v in value.iteritems():
if isinstance(v, dict):
value[k] = to_son(v)
elif isinstance(v, list):
value[k] = [to_son(x) for x in v]
return bson.son.SON(value)
# Assuming the order of the dictionary is as you desired.
to_son(a_nested_dict)

或者利用bson作为中间格式

from bson import CodecOptions, SON, BSON
nested_bson = BSON.encode(a_nested_dict)
nested_son = BSON.decode(nested_bson, codec_options=CodecOptions(document_class=SON))

SON 格式后,您可以使用 SON.to_dict() 转换回 Python 字典

关于python - Pymongo replace_one modified_count 总是 1 即使没有改变任何东西,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39599480/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com