11

指定:接続はSafe = Trueであるため、Updateの戻り値には更新情報が含まれます。

次のようなドキュメントがあるとします。

[{'a': [1]}, {'a': [2]}, {'a': [1,2]}]

そして私は発行します:

coll.update({}, {'$addToSet': {'a':1}}, multi=True)

結果は次のようになります。

{u'connectionId': 28,
 u'err': None,
 u'n': 3,
 u'ok': 1.0,
 u'updatedExisting': True
}

来たとしても、ドキュメントにはすでにその価値があります。これを回避するために、コマンドを発行できます。

coll.update({'a': {'$ne': 1}}, {'$push': {'a':1}}, multi=True)

$endToSetと$neチェックを使用した$pushの時間計算量の比較は何ですか?

4

3 に答える 3

18

$addToSetがコマンドと同じことをしているように見えます: $neチェック付きの$push。両方ともO(N)になります

https://github.com/mongodb/mongo/blob/master/src/mongo/db/ops/update_internal.cpp

速度が本当に重要な場合は、ハッシュを使用してみませんか。

それ以外の:

{'$addToSet': {'a':1}}
{'$addToSet': {'a':10}}

使用する:

{$set: {'a.1': 1}
{$set: {'a.10': 1}
于 2012-12-04T10:58:10.500 に答える
2

編集

質問を間違って読んだので、実際には2つの異なるクエリを調べて、それらの間の時間計算量を判断していることがわかりました。

最初のクエリは次のとおりです。

coll.update({}, {'$addToSet': {'a':1}}, multi=True)

そして2番目は:

coll.update({'a': {'$ne': 1}}, {'$push': {'a':1}}, multi=True)

ここで最初の問題が思い浮かびます。インデックスはありません。$addToSet、更新修飾子であるため、必要なことを実行するために全表スキャンを実行しているようなインデックスを使用しているとは思いません。

1実際には、まだ含まれていないすべてのドキュメントを探し、その配列の値をa探しています。$push1a

したがって、最初のクエリは次のようになるため、ここで時間計算量に入る前でも、2は2番目のクエリを指します。

  • インデックスを使用しません
  • 全表スキャンになります
  • 次に、(インデックスなしで)フルアレイスキャンを実行します$addToSet

ですから、私はここで、2番目のクエリがBigO表記の前に探しているものであることをほぼ決心しました。

ここで各クエリの時間計算量を説明するために大きなO表記を使用することには問題があります。

  • ドキュメントごとなのか、コレクション全体に対するものなのか、どのような視点が必要かわかりません。
  • インデックス自体はわかりません。インデックスを使用すると、実際にはログアルゴリズムが作成されますが、インデックスをa使用しない場合は作成されません。

ただし、最初のクエリは次のようになります。ドキュメントごとのO(n)以降:

  • $ addToSetは、各要素を反復処理する必要があります
  • $ addToSetは、セットが存在しない場合、セットを挿入するためにO(1)操作を実行する必要があります。O(1)がキャンセルされているかどうかわからないことに注意する必要があります(軽い読みが私のバージョンを示唆しています)、ここでキャンセルしました。

コレクションごとに、インデックスがない場合は次のようになります。反復の複雑さはa新しいドキュメントごとに指数関数的に増加するため、O(2n2)になります。

インデックスがない場合の2番目のクエリは、次のようになります。O(2n2)(ドキュメントごとにO(n))インデックスがない$ne場合と同じ問題が発生するため、私は信じてい$addToSetます。ただし、インデックスの場合、これは実際にはO(log n log n)(O(log n)per document)になると思います。これは、bツリーに基づいて、最初にすべてのドキュメントが含まaれ、次にすべてのドキュメントがセットに含まれないためです。1

したがって、時間計算量と最初のメモに基づいて、クエリ2の方が優れていると思います。

正直なところ、「ビッグO」表記で説明することに慣れていないので、これは実験的なものです。

それが役に立てば幸い、

于 2012-09-01T18:35:22.947 に答える
2

addToSetと100kドキュメントの一括更新からのプッシュの違いについての私の観察を追加します。

一括更新を行う場合。addToSetは個別に実行されます。

例えば、

bulkInsert.find({x:y}).upsert().update({"$set":{..},"$push":{ "a":"b" } , "$setOnInsert":  {} })

最初にドキュメントを挿入して設定します。次に、addToSetクエリを実行します。

私は10kの明確な違いを見ました

db.collection_name.count() #gives around 40k 

db.collection_name.count({"a":{$in:["b"]}}) # it gives only around 30k

ただし、$addToSetを$pushに置き換えると。両方のカウントクエリが同じ値を返しました。

注:配列内の重複エントリについて心配していない場合。$pushで行くことができます。

于 2015-12-10T07:14:23.847 に答える