Mongoose v3.6+**はバッチ挿入をサポートしていますか?数分間検索してみましたが、このクエリにマッチするものは数年前のもので、答えは明白にノーでした。
編集する:
今後の参考までに、答えは Model.create()
を使うことです。create()`は第一引数に配列を受け取るので、挿入するドキュメントを配列として渡すことができます。
Model.create()ドキュメント]1を参照。
Model.create()
は、非常に大きなバルクを扱っている場合、挿入を行うには悪い方法です。非常に遅いことになります。そのような場合は、Model.collection.insert
を使用する必要があり、これは ずっと良いパフォーマンスを発揮します**。バルクのサイズによっては、Model.create()
がクラッシュすることさえあります!100万個のドキュメントで試してみましたが、ダメでした。Model.collection.insert``を使用すると、数秒しかかかりませんでした。
Model.collection.insert(docs, options, callback)
docs
は挿入されるドキュメントの配列です;options
はオプションの設定オブジェクトです - the docs を参照してください。callback(err, docs)
はすべてのドキュメントが保存された後、またはエラーが発生した後に呼び出されます。成功した場合、docsは永続化されたドキュメントの配列になります。Mongoose's authorが指摘しているようにこちら、このメソッドは検証手順をバイパスしてMongoドライバに直接アクセスすることになります。大量のデータを扱うので、これはトレードオフの関係にあり、そうでなければデータベースに挿入することはできません (ここでは何十万ものドキュメントを扱っていることを忘れないでください)。
var Potato = mongoose.model('Potato', PotatoSchema);
var potatoBag = [/* a humongous amount of potato objects */];
Potato.collection.insert(potatoBag, onInsert);
function onInsert(err, docs) {
if (err) {
// TODO: handle error
} else {
console.info('%d potatoes were successfully stored.', docs.length);
}
}
Update 2019-06-22: insert()
はまだ問題なく使えますが、insertMany()
に取って代わられ非推奨となりました。パラメータは全く同じなので、これを代替品として使えばすべてうまくいくはずです(まあ、戻り値は少し違いますが、どうせ使っていないでしょう)。
使用法:
var rawDocuments = [/* ... */];
Book.insertMany(rawDocuments)
.then(function(mongooseDocuments) {
/* ... */
})
.catch(function(err) {
/* Error handling */
});
または。
Book.insertMany(rawDocuments, function (err, mongooseDocuments) { /* Your callback function... */ });
追跡できます:
実際、Mongooseの"create"メソッドを使えば、ドキュメントの配列を格納することが可能です:
Candy.create({ candy: 'jelly bean' }, { candy: 'snickers' }, function (err, jellybean, snickers) {
});
コールバック関数には、挿入された文書が格納されています。 挿入されるアイテムの数がわからない場合もあるので(上記のように引数の長さは固定)、ループさせることができます:
var insertedDocs = [];
for (var i=1; i<arguments.length; ++i) {
insertedDocs.push(arguments[i]);
}
より良い解決策は、上の例で使用した Candy.create()
の代わりに Candy.collection.insert()
を使用することです(create()
は各アイテムに対して Model.save()
を呼び出しているので遅いのです)。
詳しくは、Mongoのドキュメントをご覧ください: http://docs.mongodb.org/manual/reference/method/db.collection.insert/
(ご指摘いただいたarcseldonさんに感謝します)
最高スコアの答えとして、マングースを使用してバルクインサートを実行できます。 しかし、例は機能しません。
/* a humongous amount of potatos */
var potatoBag = [{name:'potato1'}, {name:'potato2'}];
var Potato = mongoose.model('Potato', PotatoSchema);
Potato.collection.insert(potatoBag, onInsert);
function onInsert(err, docs) {
if (err) {
// TODO: handle error
} else {
console.info('%d potatoes were successfully stored.', docs.length);
}
}
バルクインサートにスキーマインスタンスを使用しないでください。プレーンマップオブジェクトを使用する必要があります。
insertManyでデータを保存する方法と保存する方法の両方を次に示します。
1)「insertMany」をまとめて、一連のドキュメントを保存します。
/* write mongoose schema model and export this */
var Potato = mongoose.model('Potato', PotatoSchema);
/* write this api in routes directory */
router.post('/addDocuments', function (req, res) {
const data = [/* array of object which data need to save in db */];
Potato.insertMany(data)
.then((result) => {
console.log("result ", result);
res.status(200).json({'success': 'new documents added!', 'data': result});
})
.catch(err => {
console.error("error ", err);
res.status(400).json({err});
});
})
。save()
を使用して、ドキュメントの配列をマングースに保存します。これらのドキュメントは並行して保存されます。
/* write mongoose schema model and export this */
var Potato = mongoose.model('Potato', PotatoSchema);
/* write this api in routes directory */
router.post('/addDocuments', function (req, res) {
const saveData = []
const data = [/* array of object which data need to save in db */];
data.map((i) => {
console.log(i)
var potato = new Potato(data[i])
potato.save()
.then((result) => {
console.log(result)
saveData.push(result)
if (saveData.length === data.length) {
res.status(200).json({'success': 'new documents added!', 'data': saveData});
}
})
.catch((err) => {
console.error(err)
res.status(500).json({err});
})
})
})
マングースを使用する場合、1000を超えるドキュメントの制限があるようです。
Potato.collection.insert(potatoBag, onInsert);
あなたは使うことができます:
var bulk = Model.collection.initializeOrderedBulkOp();
async.each(users, function (user, callback) {
bulk.insert(hash);
}, function (err) {
var bulkStart = Date.now();
bulk.execute(function(err, res){
if (err) console.log (" gameResult.js > err " , err);
console.log (" gameResult.js > BULK TIME " , Date.now() - bulkStart );
console.log (" gameResult.js > BULK INSERT " , res.nInserted)
});
});
しかし、これは10000のドキュメントでテストする場合のほぼ2倍の速さです。
function fastInsert(arrOfResults) {
var startTime = Date.now();
var count = 0;
var c = Math.round( arrOfResults.length / 990);
var fakeArr = [];
fakeArr.length = c;
var docsSaved = 0
async.each(fakeArr, function (item, callback) {
var sliced = arrOfResults.slice(count, count+999);
sliced.length)
count = count +999;
if(sliced.length != 0 ){
GameResultModel.collection.insert(sliced, function (err, docs) {
docsSaved += docs.ops.length
callback();
});
}else {
callback()
}
}, function (err) {
console.log (" gameResult.js > BULK INSERT AMOUNT: ", arrOfResults.length, "docsSaved " , docsSaved, " DIFF TIME:",Date.now() - startTime);
});
}
同じことを達成するために、async-forEach(async-forEach npmパッケージのドキュメントのリンク)を使用しました。
コードスニペットは以下のとおりです。ドキュメントをreq.bodyで取得しています。
var forEach = require('async-foreach').forEach;
exports.save_Ctrl = function (req, res) {
// var l=req.body;
// console.log("length:",l.length);
forEach(req.body, function(item, index, object,err) {
console.log(req.body[index]);
var post = new saveObj(req.body[index]);
//save model to MongoDB
post.save(function (err) {
if (err) {
console.log('error saving :' + err.message);
return err;
}
else {
console.log("Post saved");
}
});
});
}
私たちのプロジェクトからの作業と関連するコードの共有:
//documentsArray is the list of sampleCollection objects
sampleCollection.insertMany(documentsArray)
.then((res) => {
console.log("insert sampleCollection result ", res);
})
.catch(err => {
console.log("bulk insert sampleCollection error ", err);
});