LoginSignup
8
9

More than 5 years have passed since last update.

MongoDB Bulk Methodを使う

Last updated at Posted at 2015-08-05

Bulk Method とは

2.6から実装された、大量にinsert、updateを行うときに
効率よく処理してくれる便利な物

実装以前

db.table_name.insert([{docA}, {docB}, {docC}])

こんな感じで配列で渡してあげることで実現してた

使って見る

var bulk = db.tbl_name.initializeUnorderedBulkOp();
bulk.insert ({docA});
bulk.insert ({docB});
bulk.insert ({docC});
bulk.execute();

まず、bulkオブジェクトを生成しその後に実行したい操作をつんでいく
最後にexecuteメソッドを利用して反映。

bulkオブジェクトには、 initializeUnorderedBulkOpinitializeOrderedBulkOp が存在する。

UnorderedとOrederd

エラー発生時にそのまま続けるかどうか

main.js
var try_bulk_insert = function(bulk) {
  bulk.find({}).remove();
  bulk.insert(datas[5000]);
  datas.forEach(function(i) { bulk.insert (i) });

  try {
    bulk.execute();
  } catch (e) {
    printjson(e);
  }
}

try_bulk_insert(
  db.tbl_insert_unorderd_bulk.initializeUnorderedBulkOp()
);

try_bulk_insert(
  db.tbl_insert_orderd_bulk.initializeOrderedBulkOp()
);

結果
Orederdはエラー発生で処理を中断しているが
Unorderedは可能な限り実行している

{
    "writeErrors" : [
        {
            "index" : 5002,
            "code" : 11000,
            "errmsg" : "E11000 duplicate key error collection: test.tbl_insert_unorderd_bulk index: _id_ dup key: { : ObjectId('xxxxx') }",
            "op" : {
                "_id" : ObjectId("xxxxx"),
                "skey" : 89,
                "user_id" : 1752659,
                "area_id" : 3,
                "comp" : 2,
                "map_id" : 1
            }
        }
    ],
    "writeConcernErrors" : [ ],
    "nInserted" : 100000,
    "nUpserted" : 0,
    "nMatched" : 0,
    "nModified" : 0,
    "nRemoved" : 0,
    "upserted" : [ ]
}
{
    "writeErrors" : [
        {
            "index" : 5002,
            "code" : 11000,
            "errmsg" : "E11000 duplicate key error collection: test.tbl_insert_orderd_bulk index: _id_ dup key: { : ObjectId('xxxxx') }",
            "op" : {
                "_id" : ObjectId("xxxxx"),
                "skey" : 89,
                "user_id" : 1752659,
                "area_id" : 3,
                "comp" : 2,
                "map_id" : 1
            }
        }
    ],
    "writeConcernErrors" : [ ],
    "nInserted" : 5001,
    "nUpserted" : 0,
    "nMatched" : 0,
    "nModified" : 0,
    "nRemoved" : 0,
    "upserted" : [ ]
}

計測する

main.js
//
// 10万件のデータ,以下の形式のファイルを読み込み
// var datas = [ { object }, {object} ];
//
load("./tbl_data.json");

var measure = function(tag, target_func)
{
   var startTime = new Date();
   target_func();
   var endTime = new Date();

   print(tag + " : " + (endTime - startTime) + "ms");
};

// 一件ずつinsert
measure("insert 1", function() {
  datas.forEach(function(i) {db.tbl_insert.insert (i) });
});

// 1000件ずつ配列によるBulkinsert
measure("insert 2", function() {
  for (var i = 0; i < datas.length; i += 1000) {
    db.tbl_insert_bulk.insert( datas.slice(i, i + 1000) );
  }
});

// BulkMethodを利用したinsert
measure("insert 3", function() {
  var bulk = db.tbl_bulk.initializeUnorderedBulkOp();
  datas.forEach(function(i) { bulk.insert (i) });
  bulk.execute();
});

実行結果

$ mongo main.js 
MongoDB shell version: 3.0.5
connecting to: test
insert 1 : 53365ms
insert 2 : 5903ms
insert 3 : 6138ms

結果

バッチ処理で今回のような大量にinsertすることがあると思う。
こういうときは BulkInsert を利用する。

数十件レベルであれば、配列によるBulkInsertで問題ない

数千件を超えてくる場合であればBulkMethodを使うほうが
自分でスライスしたり調整しなくていいので楽かなと

8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9