2016-09-20 6 views
2

どうしてこのように動作しますか?Pymongo replace_one modified_countは何も変更していなくても常に1です

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のシェルの等価は常に0

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

ときにどのように私は一貫性のある結果を得ることができ、交換は、実際にデータを変更したとき、適切に検出しますか?

+1

MongoDBとpymongoのバージョンは何ですか? –

+0

@KevinAdistambha 3.2.7とpymongo 3.3もpymongoにダウングレードしようとしました3.2.2 –

+0

修正する前にドキュメントを返して結果を比較するが、なぜこれがうまくいかなかったのかを知りたい 'find_one_and_replace'でこれを解決しました。私は実際にpre.pdfドキュメントを検索する気にはならないので、これは最適ではない –

答えて

3

これは、MongoDBが文書をバイナリ(BSON)形式で保存するためです。 BSON文書のキーと値のペアは、任意の順序を持​​つことができます(ただし、_idが常に先頭です)。 最初にmongo shellから始めましょう。 mongoシェルは、データの読み書き時にキー順を保持します。たとえば :あなたはこの文書の値を使用してreplaceOne()を実行している場合、既存のBSONがありますので

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

、それは修正を避けるだろう。

> 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はデフォルトでPython辞書としてのBSON文書を表し、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} 

それはあなたのユースケースのために重要な場合は、1つの回避策は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にネストされた辞書を変換する「標準」の機能はありません。、あなたを

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) 

するか、SON形式で

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)) 

一度中間フォーマットとしてBSONを利用:カスタムを書くことができますがdictSONには、例えば、自分自身をコンバータSON.to_dict()

0を使ってPython辞書に戻すことができます
+0

これは理にかなっています!ネストされたdictをSONに再帰的にキャストする標準的な関数があるかどうか知っていますか? –

+0

「標準」機能はないと思いますが、更新された回答を確認してください。 –

関連する問題