Pymongo replace_一个修改的\u count始终为1,即使不更改任何内容

2024-10-05 10:20:24 发布

您现在位置:Python中文网/ 问答频道 /正文

为什么,怎么会这样?在

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时

^{pr2}$

我怎样才能得到一致的结果,并正确地检测到替换者实际上在更改数据?在


Tags: testtruedbrawokresultfinditem
1条回答
网友
1楼 · 发布于 2024-10-05 10:20:24

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

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

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

^{pr2}$

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

> 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。在

更新回答另一个问题:

据我所知,没有一个“标准”函数可以将嵌套字典转换为子字典。尽管您可以自己编写一个自定义的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字典

相关问题 更多 >

    热门问题