目前我使用保存添加單個文檔。假設我有一組我希望作爲單個對象存儲的文檔。有沒有一種方法可以通過單個函數調用添加它們,然後在完成時獲取單個回調?我可以單獨添加所有文檔,但管理回調以確定何時完成所有操作都會產生問題。如何在Mongoose/Node.js中同時保存多個文檔?
回答
貓鼬沒有實現批量插入(請參閱issue #723)。
既然你知道你保存文件的數量,你可以寫這樣的事情:
var total = docArray.length
, result = []
;
function saveAll(){
var doc = docArray.pop();
doc.save(function(err, saved){
if (err) throw err;//handle error
result.push(saved[0]);
if (--total) saveAll();
else // all saved here
})
}
saveAll();
這當然是一種權宜的解決方案,我會建議使用某種流 - 控制庫(我使用q,它很棒)。
您可以使用q提供解決方案嗎? – Manu 2015-04-22 07:19:34
我不認爲這是「併發」。直到前一個完成後纔會調用每個保存。 – 2015-06-24 00:22:19
是的。例如,一個更加併發的方法是,將所有的「保存」都燒掉,等待所有人調用它們的回調並返回一組結果。您可以使用async或某種承諾界面。 – diversario 2015-06-24 04:15:08
這裏是不使用額外的庫的另一種方式(檢查包括無差錯)
function saveAll(callback){
var count = 0;
docs.forEach(function(doc){
doc.save(function(err){
count++;
if(count == docs.length){
callback();
}
});
});
}
貓鼬不現在支持傳遞多個文件結構,以Model.create。引述他們的API例如,它支持傳遞數組或在年底有一個回調對象的可變參數列表:
Candy.create({ type: 'jelly bean' }, { type: 'snickers' }, function (err, jellybean, snickers) {
if (err) // ...
});
或者
var array = [{ type: 'jelly bean' }, { type: 'snickers' }];
Candy.create(array, function (err, jellybean, snickers) {
if (err) // ...
});
編輯:正如許多人所指出的,這不會執行真正的批量插入 - 它只是隱藏了自己多次調用save
的複雜性。下面的答案和評論解釋瞭如何使用實際的Mongo驅動程序來實現批量插入以實現性能。
注意:這不是一個BULK插入 - 底層的mongoose實現循環遍歷所有元素並逐一提交它們。 – outside2344 2014-05-24 14:08:16
^這是非常相關的,因爲它可能嚴重影響那些使用它的人的表現。 – 2014-06-13 10:06:40
對Aaron Heckman 2011的迴應:並非如此。 Model.create(doc1 [,docN],回調)在這裏有幫助,但它仍然在每一個調用model.save。 如果「快」你的意思是「超越所有的貓鼬掛鉤和驗證」,那麼你可以下降到本地驅動程序,直接使用它: Movie.collection.insert(文檔,期權,回調) HTTPS:/ /github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L96-113 – arcseldon 2014-07-24 19:16:17
添加一個名爲mongoHelper.js
var MongoClient = require('mongodb').MongoClient;
MongoClient.saveAny = function(data, collection, callback)
{
if(data instanceof Array)
{
saveRecords(data,collection, callback);
}
else
{
saveRecord(data,collection, callback);
}
}
function saveRecord(data, collection, callback)
{
collection.save
(
data,
{w:1},
function(err, result)
{
if(err)
throw new Error(err);
callback(result);
}
);
}
function saveRecords(data, collection, callback)
{
save
(
data,
collection,
callback
);
}
function save(data, collection, callback)
{
collection.save
(
data.pop(),
{w:1},
function(err, result)
{
if(err)
{
throw new Error(err);
}
if(data.length > 0)
save(data, collection, callback);
else
callback(result);
}
);
}
module.exports = MongoClient;
文件然後在你的代碼更改你要求
var MongoClient = require("./mongoHelper.js");
然後,當它的時間來保存呼叫(已連接並取回了收集後)
MongoClient.saveAny(data, collection, function(){db.close();});
您可以更改錯誤處理以滿足您的需要,錯誤回調等
使用async parallel和你的代碼看起來就像這樣:
async.parallel([obj1.save, obj2.save, obj3.save], callback);
因爲公約是貓鼬一樣異步(ERR,回調)你不需要包他們在你自己的回調中,只需將你的保存調用添加到一個數組中,當全部完成時你將得到一個回調。
如果您使用mapLimit,則可以控制要並行保存多少個文檔。在這個例子中,我們並行地保存了10個文檔,直到所有項目都成功保存。
async.mapLimit(myArray, 10, function(document, next){
document.save(next);
}, done);
有意思 - 你會介意給一個現實世界可用的例子,帶一個'myArray';而myArray擁有1000萬件物品。 – nottinhill 2015-02-24 17:52:00
使用mapLimits更新了一個單獨的示例 – 2015-02-25 15:28:09
非常酷的使用異步! – 2016-02-03 02:04:02
我知道這是一個老問題,但我很擔心,有沒有正確的正確答案在這裏。大多數的答案只是談論過的所有文件單獨迭代和保存他們每個人,這是一個壞主意,如果你擁有很多的文件多了,過程被重複,甚至一個在許多請求。
的MongoDB專門有一個batchInsert()
呼籲將多個文檔,這應該從本地MongoDB的驅動程序一起使用。 Mongoose建立在此驅動程序上,並且不支持批量插入。這可能是有道理的,因爲它應該是MongoDB的Object文檔建模工具。
解決方案:貓鼬自帶的本地MongoDB的驅動程序。你可以要求它require('mongoose/node_modules/mongodb')
使用的驅動程序(也不太清楚這一點,但你總是可以重新安裝MongoDB的NPM,如果它不工作,但我認爲它應該),然後做一個適當的batchInsert
錯誤,帕斯卡的回答完全忽略了這一觀點。需要批量插入的人往往需要它,因爲他們想要一次插入10,000,000個項目。如果沒有批量插入,需要幾秒鐘的操作可能需要幾小時。 Model.create是一個史詩般的失敗,因爲它假裝是一個批量插入,但在引擎蓋下它只是一個for循環。 – user3690202 2014-06-23 01:03:25
然後,貓鼬嚴重需要一些改造。他們的文件也留下了很多希望。 – nottinhill 2014-09-17 15:49:52
我想@Yashua的問題通過使用基礎的'mongodb' javascript驅動來解決它。 – 2014-11-26 18:41:09
批量插入在Mongoose中可以用.insert()來完成,除非你需要訪問中間件。
Model.collection.insert(docs, options, callback)
https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L71-91
2011年亞倫赫克曼的迴應:不是真的。 Model.create(doc1 [,docN],回調)在這裏有幫助,但它仍然在每一個調用model.save。 如果「快」你的意思是「超越所有的貓鼬掛鉤和驗證」,那麼你可以下降到本地驅動程序,直接使用它: Movie.collection.insert(文檔,期權,回調) HTTPS:/ /github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L96-113 – arcseldon 2014-07-24 19:14:21
我一直在看這個答案,但這並不是真正的「貓鼬」做事方式。這完全繞過了Mongoose模型。如果您爲貓鼬模型中的某些字段設置了默認值,則它們將被忽略,並且不會插入到數據庫中。 – Nahn 2014-09-04 12:55:17
如何在Mongoose中使用'Model.collection.insert'?請舉一個例子。 – nottinhill 2014-09-17 15:51:06
較新版本的MongoDB支持批量操作的:
var col = db.collection('people');
var batch = col.initializeUnorderedBulkOp();
batch.insert({name: "John"});
batch.insert({name: "Jane"});
batch.insert({name: "Jason"});
batch.insert({name: "Joanne"});
batch.execute(function(err, result) {
if (err) console.error(err);
console.log('Inserted ' + result.nInserted + ' row(s).');
}
您可以使用貓鼬save
返回的承諾,Promise
在貓鼬並非全部,但你可以添加此模塊的功能。
創建加強與所有的貓鼬承諾的模塊。
var Promise = require("mongoose").Promise;
Promise.all = function(promises) {
var mainPromise = new Promise();
if (promises.length == 0) {
mainPromise.resolve(null, promises);
}
var pending = 0;
promises.forEach(function(p, i) {
pending++;
p.then(function(val) {
promises[i] = val;
if (--pending === 0) {
mainPromise.resolve(null, promises);
}
}, function(err) {
mainPromise.reject(err);
});
});
return mainPromise;
}
module.exports = Promise;
然後用貓鼬使用它:
var Promise = require('./promise')
...
var tasks = [];
for (var i=0; i < docs.length; i++) {
tasks.push(docs[i].save());
}
Promise.all(tasks)
.then(function(results) {
console.log(results);
}, function (err) {
console.log(err);
})
這是一個老問題,但它在谷歌搜索結果「的文件貓鼬插件組」當走到第一個我。
有兩個選項model.create()[貓鼬]和model.collection.insert()的MongoDB]您可以使用。查看更深入的討論這裏的每個選項的利弊/利弊:
下面是使用的例子MongoDB的Model.collection.insert()
直接在貓鼬。請注意,如果你沒有那麼多文件,即少於100個文件,就不需要使用MongoDB的批量操作(see this)。
MongoDB也通過傳遞的 文檔的陣列到db.collection.insert()方法支持大容量插入。
var mongoose = require('mongoose');
var userSchema = mongoose.Schema({
email : { type: String, index: { unique: true } },
name : String
});
var User = mongoose.model('User', userSchema);
function saveUsers(users) {
User.collection.insert(users, function callback(error, insertedDocs) {
// Here I use KrisKowal's Q (https://github.com/kriskowal/q) to return a promise,
// so that the caller of this function can act upon its success or failure
if (!error)
return Q.resolve(insertedDocs);
else
return Q.reject({ error: error });
});
}
var users = [{email: '[email protected]', name: 'foo'}, {email: '[email protected]', name: 'baz'}];
saveUsers(users).then(function() {
// handle success case here
})
.fail(function(error) {
// handle error case here
});
哪個貓鼬版本是這個? – R01010010 2016-05-14 02:37:20
貓鼬4。4增加了一個名爲insertMany
快捷用於驗證文件的數組,並將其插入到 MongoDB中,如果他們所有的有效方法。此函數比.create()更快,因爲它只向服務器發送一個操作,而不是每個 文檔都發送一個操作。
從問題#723報價vkarpov15:
的權衡是insertMany()不會觸發預存掛鉤,但它應該有更好的表現,因爲它不僅使1往返的數據庫而不是每個文檔1。
方法的簽名是相同的create
:
Model.insertMany([ ... ], (err, docs) => {
...
})
或者與承諾:
Model.insertMany([ ... ]).then((docs) => {
...
}).catch((err) => {
...
})
謝謝你。它表示如果它們全部有效,它會插入它們;這是否意味着如果一個失敗都會失敗? – Aron 2016-12-15 23:04:39
這是一個批量操作,但它不是原子的。我不確定Mongoose是如何做的,現在不能測試,但它應該返回成功寫入的次數。在MongoDB的文檔中有更多的細節:https://docs.mongodb.com/manual/reference/method/db.collection.insertMany/#error-handling – 2016-12-16 15:23:17
這是完美的和最新的答案!謝謝 – 2017-03-06 09:17:30
使用insertMany
功能的嵌入式許多文件。這隻會向服務器發送一個操作,並在打到mongo服務器之前驗證所有文檔。默認情況下,Mongoose
按照它們在數組中存在的順序插入項目。如果您沒有維護任何訂單,請確定ordered:false
。
重要 - 錯誤處理:如果一個失敗,一切都將失敗
當ordered:true
驗證和錯誤處理組中發生手段。
當ordered:false
驗證和錯誤處理單獨發生並且操作將繼續。錯誤將以一系列錯誤報告。
- 1. 同時保存兩個參考文檔
- 2. ssjs保存多個文檔
- 3. 如何在Lucene中存儲多個不同類型的文檔
- 4. 在HTML中保存副本時如何保留原始文檔文檔?
- 5. 如何在Java中保存DOM文檔?
- 6. 如何保存/更新貓鼬中的多個文檔
- 7. PolymerFire - 如何保存文檔?
- 8. 一次保存多個文檔 - Mongoose.js
- 9. 同時保存子文檔引用和父文檔
- 10. 如何將行保存在變量中並保存excel文檔?
- 11. 同時存檔多個目標
- 12. 在mongoDb中保存文檔
- 13. 如何讓MATLAB的多個實例同時保存同一個文件
- 14. 在CakePHP中同時保存manys用戶及其個人檔案
- 15. 谷歌文檔如何同時同步兩個文檔?
- 16. 在同一文檔中同時進行多個更新
- 17. 無法在GridFS中保存多個文檔(使用MongoMapper/Joint)
- 18. 如何在mongodb中存儲同一個集合中的許多文檔
- 19. 如何在多個頁面中將Excel表格保存爲Word文檔
- 20. 如何在一個文本文件中保存多個數據
- 21. 如何在stata中的同一文檔中排出多個表?
- 22. 用貓鼬保存多個文檔時處理錯誤
- 23. 如何在Rails中同時保存很多has_many_through對象?
- 24. 同時保存多個HABTM機型
- 25. 如何將文件保存在文檔文件夾中?
- 26. 如何在html文檔中存在多個圖像時定位圖像
- 27. 如何同時保存NSDocument?
- 28. XSLT - 如何從另一個臨時文檔中的一個文檔中保存節點並稍後檢索它?
- 29. 如何在mongodb中不存在某個鍵時插入文檔
- 30. Bluemix NodeRed - 如何在Cloudant DB中一次存儲多個文檔?
您需要控制代碼流使用某種異步庫,如異步。 (有並行功能,當完成回調調用時) – 2012-04-22 08:47:27
https://groups.google.com/forum/#!topic/mongoose-orm/IkPmvcd0kds – arcseldon 2014-07-24 19:18:29