MongoDB
バルク操作
サーチ…
備考
単一のコレクションに対して一括して実行する書き込み操作のリストを作成する
フィールドを別のタイプに変換し、コレクション全体を一括で更新する
通常、元のコレクションに文字列として保存された「数値」フィールドまたは「日付」フィールドがあるなど、フィールドタイプを別のものに変更する場合は、
{
"name": "Alice",
"salary": "57871",
"dob": "1986-08-21"
},
{
"name": "Bob",
"salary": "48974",
"dob": "1990-11-04"
}
目的は、上記のような膨大なコレクションを更新することです。
{
"name": "Alice",
"salary": 57871,
"dob": ISODate("1986-08-21T00:00:00.000Z")
},
{
"name": "Bob",
"salary": 48974,
"dob": ISODate("1990-11-04T00:00:00.000Z")
}
比較的小さなデータの場合、カーソルのforEach()
メソッドを使用してsnapshot
を使用してコレクションを反復し、各ドキュメントを次のように更新することによって、上記を達成できます。
db.test.find({
"salary": { "$exists": true, "$type": 2 },
"dob": { "$exists": true, "$type": 2 }
}).snapshot().forEach(function(doc){
var newSalary = parseInt(doc.salary),
newDob = new ISODate(doc.dob);
db.test.updateOne(
{ "_id": doc._id },
{ "$set": { "salary": newSalary, "dob": newDob } }
);
});
これは小規模なコレクションには最適ですが、大規模なデータセットをループし、サーバーに要求ごとに各更新操作を送信すると計算上のペナルティが発生するため、大規模なコレクションのパフォーマンスが大幅に低下します。
Bulk()
APIは、書き込み操作がバルクで一度だけサーバーに送信されるため、レスキューになり、パフォーマンスが大幅に向上します。このメソッドは、(現在のforEach()
ループ内の現在の更新ステートメントのように)サーバーにすべての書き込み要求を送信するのではなく、1000リクエストごとに1回しか送信しないため、現在よりも効率的で迅速な更新が可能です。
上記のforEach()
ループと同じ概念を使用してバッチを作成すると、次のように一括でコレクションを更新できます。このデモンストレーションでは、MongoDBバージョン>= 2.6
および< 3.2
使用可能なBulk()
APIは、 initializeUnorderedBulkOp()
メソッドを使用して、バッチ内の書き込み操作と並行して非決定的な順序で実行します。
salary
フィールドとdob
フィールドをそれぞれnumerical
とdatetime
値に変更することによって、クライアントコレクション内のすべてのドキュメントを更新します。
var bulk = db.test.initializeUnorderedBulkOp(),
counter = 0; // counter to keep track of the batch update size
db.test.find({
"salary": { "$exists": true, "$type": 2 },
"dob": { "$exists": true, "$type": 2 }
}).snapshot().forEach(function(doc){
var newSalary = parseInt(doc.salary),
newDob = new ISODate(doc.dob);
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "salary": newSalary, "dob": newDob }
});
counter++; // increment counter
if (counter % 1000 == 0) {
bulk.execute(); // Execute per 1000 operations and re-initialize every 1000 update statements
bulk = db.test.initializeUnorderedBulkOp();
}
});
次の例は、以来、 Bulk()
APIを廃止し、 bulkWrite()
を使用して新しいapisセットを提供した新しいMongoDBバージョン3.2
適用されます。
上記と同じカーソルを使用しますが、同じforEach()
カーソルメソッドを使用して一括操作で配列を作成し、一括書き込みドキュメントを配列にプッシュします。書き込みコマンドは1000回を超える操作を受け入れることができないため、1000回以下の操作をグループ化して、ループが1000回の繰り返しに当たるとアレイを再初期化する必要があります。
var cursor = db.test.find({
"salary": { "$exists": true, "$type": 2 },
"dob": { "$exists": true, "$type": 2 }
}),
bulkUpdateOps = [];
cursor.snapshot().forEach(function(doc){
var newSalary = parseInt(doc.salary),
newDob = new ISODate(doc.dob);
bulkUpdateOps.push({
"updateOne": {
"filter": { "_id": doc._id },
"update": { "$set": { "salary": newSalary, "dob": newDob } }
}
});
if (bulkUpdateOps.length === 1000) {
db.test.bulkWrite(bulkUpdateOps);
bulkUpdateOps = [];
}
});
if (bulkUpdateOps.length > 0) { db.test.bulkWrite(bulkUpdateOps); }