Adr*_*ián 5 python mongodb pymongo
为什么以及如何像这样工作?
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
Run Code Online (Sandbox Code Playgroud)
当 mongodb shell 中的等效项始终为 0 时
item = db.test.findOne()
db.test.replaceOne(item, item)
# Gives: {"acknowledged" : true, "matchedCount" : 1.0, "modifiedCount" : 0.0}
Run Code Online (Sandbox Code Playgroud)
如何获得一致的结果并正确检测替换何时实际更改数据?
这是因为 MongoDB 以二进制 ( BSON ) 格式存储文档。BSON 文档中的键值对可以有任何顺序(除了 _id 总是在最前面)。让我们先从mongo shell开始。mongo shell 在读写数据时会保留键顺序。例如:
> db.collection.insert({_id:1, a:2, b:3})
{ "_id" : 1, "a" : 2, "b" : 3 }
Run Code Online (Sandbox Code Playgroud)
如果您使用此文档值执行replaceOne(),它将避免修改,因为存在一个现有的 BSON。
> var doc = db.collection.findOne()
> db.collection.replaceOne(doc, doc)
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }
Run Code Online (Sandbox Code Playgroud)
但是,如果您更改字段的顺序,它将检测到修改
> var doc_2 = {_id:1, b:3, a:2}
> db.collection.replaceOne(doc_2, doc_2)
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
Run Code Online (Sandbox Code Playgroud)
让我们走进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}
Run Code Online (Sandbox Code Playgroud)
如果这对您的用例很重要,一种解决方法是使用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}
Run Code Online (Sandbox Code Playgroud)
您还可以观察到bson.SONPyMongo (v3.3.0) 中使用的_update() 方法。另请参阅相关文章:PyMongo 和 SubDocuments 中的关键顺序。
更新以回答其他问题:
据我所知,没有将嵌套字典转换为 SON 的“标准”函数。虽然你可以编写自定义dict到SON转换器自己,例如:
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)
Run Code Online (Sandbox Code Playgroud)
或者使用 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))
Run Code Online (Sandbox Code Playgroud)
一旦SON格式,您可以使用转换回Python字典SON.to_dict()
| 归档时间: |
|
| 查看次数: |
2933 次 |
| 最近记录: |