2016-10-19 5 views
1

私はmongoに保存されたメタを持つ画像ギャラリーを持っています。 Webサイトのクエリが保存された画像のいくつかの数と一致するたびに、文書shownカウンターフィールドを増分したいと思います。 findAndModifyを使用すると、1つのドキュメントで正常に動作しますが、複数のドキュメントを一致させてそれらをすべて更新するうまい方法はありません。Mongo一括検索で一致したドキュメントフィールドを一括検索して更新しますか?

これはmongoの最新バージョンで可能ですか?これを達成するためのベストプラクティスをお勧めしますか?

おかげ FLO

文書フォーマットが

{ 
"name"   : "img name", 
"description" : "some more info", 
"size"   : "img size in bytes", 
"shown"  : "count of times the image was selected by query", 
"viewed"  : "count of times the image was clicked" 
} 

非常にシンプルで、クエリは、結果をループにカーソルを使用して、文書IDを使用して示され、カウントをバンプ、シンプルな検索..ですすなわち

db.images.update(
    { _id: "xxxx" }, 
    { $inc: { shown: 1 } } 
) 

しかし、100個のドキュメントを取得しないようにして、それぞれを個別に更新する必要があります。単一のクエリで検索と更新を実行したいと考えていました。

+0

あなたは私たちにいくつかのサンプル文書と現在の更新クエリを表示することができますか? – chridam

+0

よろしくお願いします。ありがとう。 –

答えて

0

パフォーマンス向上のために、あなたはバッチで、サーバーへのオペレーションを送信するように、バルクで効率的にコレクションを更新するためのBulk() APIを使用しての利点を取る(例えば、500のバッチサイズを言います)。これにより、すべてのリクエストをサーバーに送信するのではなく、500リクエストごとに1回だけ送信するので、更新をより効率的かつ迅速に行うので、パフォーマンスが大幅に向上します。

次に、このアプローチを示し、最初の例では、MongoDBのバージョン> = 2.6及び< 3.2で利用可能Bulk() APIを使用します。このメソッドは、コレクション内の一致するすべてのドキュメントを、指定された配列から、表示されたフィールドに1ずつ増やして更新します。これは、画像のアレイ構造を有している前提

var images = [ 
    { "_id": 1, "name": "img_1.png" }, 
    { "_id": 2, "name": "img_2.png" } 
    { "_id": 3, "name": "img_3.png" }, 
    ... 
    { "_id": n, "name": "img_n.png" } 
] 

MongoDBのバージョン> = 2.6及び< 3.2

var bulk = db.images.initializeUnorderedBulkOp(), 
    counter = 0; 

images.forEach(function (doc) {  
    bulk.find({ "_id": doc._id }).updateOne({ 
     "$inc": { "shown": 1 } 
    }); 

    counter++; 
    if (counter % 500 === 0) { 
     // Execute per 500 operations 
     bulk.execute(); 
     // re-initialize every 500 update statements 
     bulk = db.images.initializeUnorderedBulkOp(); 
    } 
}) 
// Clean up remaining queue 
if (counter % 500 !== 0) { bulk.execute(); } 

次の例では、持っている新しいMongoDBのバージョン3.2に適用されdeprecated以来Bulk() APIを使用し、bulkWrite()を使用して、新しいAPIセットを提供しました。

MongoDBのバージョン3.2以上

var ops = []; 
images.forEach(function(doc) { 
    ops.push({ 
     "updateOne": { 
      "filter": { "_id": doc._id }, 
      "update": { 
       "$inc": { "shown": 1 } 
      } 
     } 
    }); 

    if (ops.length === 500) { 
     db.images.bulkWrite(ops); 
     ops = []; 
    } 
}) 

if (ops.length > 0) 
    db.images.bulkWrite(ops); 
+0

素晴らしい、多くのありがとう。今実験します。私は、一括書き込みのようなものを探していたと思うが、いくつかのメタデータを返すのではなく、更新されたドキュメントでカーソルを返したので、find()で行うように反復できる。だから私は両方の更新を達成することができ、1つのクエリで見つける。しかし、それは可能ではないようです。 –

+0

上記の例で使用した 'images'配列の代わりに、実際に' find() 'カーソルを使って一致する文書を繰り返し処理することができます。これは[**' forEach() '**](https: /docs.mongodb.com/v3.2/reference/method/cursor.forEach/)メソッドを使用することができます。 – chridam

関連する問題