Im Moment benutze ich save, um ein einzelnes Dokument hinzuzufügen. Angenommen, ich habe eine Reihe von Dokumenten, die ich als einzelne Objekte speichern möchte. Gibt es eine Möglichkeit, sie alle mit einem einzigen Funktionsaufruf hinzuzufügen und dann einen einzigen Rückruf zu erhalten, wenn dies erledigt ist? Ich könnte alle Dokumente einzeln hinzufügen, aber die Verwaltung der Rückrufe, um herauszufinden, wann alles erledigt ist, wäre problematisch.
75
Antworten:
Mongoose hat noch keine Bulk-Inserts implementiert (siehe Problem Nr. 723 ).
Da Sie die Anzahl der Dokumente kennen, die Sie speichern, können Sie Folgendes schreiben:
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();
Dies ist natürlich eine Stop-Gap-Lösung, und ich würde empfehlen, eine Art Flusskontrollbibliothek zu verwenden (ich verwende q und es ist fantastisch).
quelle
save
s auszulösen, darauf zu warten, dass alle ihren Rückruf aufrufen und eine Reihe von Ergebnissen zurückgeben. Sie könnten dafür Async oder eine vielversprechende Oberfläche verwenden.if (--total)
falsch sein?Mongoose unterstützt jetzt die Übergabe mehrerer Dokumentstrukturen an Model.create . Um das API-Beispiel zu zitieren, wird die Übergabe eines Arrays oder einer varargs-Liste von Objekten mit einem Rückruf am Ende unterstützt:
Candy.create({ type: 'jelly bean' }, { type: 'snickers' }, function (err, jellybean, snickers) { if (err) // ... });
Oder
var array = [{ type: 'jelly bean' }, { type: 'snickers' }]; Candy.create(array, function (err, jellybean, snickers) { if (err) // ... });
Bearbeiten: Wie viele angemerkt haben, führt dies keine echte Masseneinfügung durch - es verbirgt einfach die Komplexität,
save
selbst mehrmals anzurufen. Im Folgenden finden Sie Antworten und Kommentare, in denen erläutert wird, wie Sie den tatsächlichen Mongo-Treiber verwenden, um im Interesse der Leistung eine Masseneinfügung zu erzielen.quelle
Mongoose 4.4 hat eine Methode namens hinzugefügt
insertMany
Zitiert vkarpov15 aus Ausgabe # 723 :
Die Signatur der Methode ist identisch mit
create
:Model.insertMany([ ... ], (err, docs) => { ... })
Oder mit Versprechungen:
Model.insertMany([ ... ]).then((docs) => { ... }).catch((err) => { ... })
quelle
Masseneinfügungen in Mongoose können mit .insert () durchgeführt werden, es sei denn, Sie müssen auf Middleware zugreifen.
Model.collection.insert(docs, options, callback)
https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L71-91
quelle
Model.collection.insert
in Mungo? Bitte geben Sie ein Beispiel.Verwenden Sie asynchron parallel und Ihr Code sieht folgendermaßen aus:
async.parallel([obj1.save, obj2.save, obj3.save], callback);
Da die Konvention in Mongoose dieselbe ist wie in asynchron (err, callback), müssen Sie sie nicht in Ihre eigenen Rückrufe einschließen. Fügen Sie einfach Ihre gespeicherten Aufrufe in ein Array ein, und Sie erhalten einen Rückruf, wenn alles abgeschlossen ist.
Wenn Sie mapLimit verwenden, können Sie steuern, wie viele Dokumente Sie parallel speichern möchten. In diesem Beispiel speichern wir 10 Dokumente parallel, bis alle Elemente erfolgreich gespeichert wurden.
async.mapLimit(myArray, 10, function(document, next){ document.save(next); }, done);
quelle
myArray
? Während myArray 10 Millionen Artikel hat.Ich weiß, dass dies eine alte Frage ist, aber es macht mir Sorgen, dass es hier keine richtig richtigen Antworten gibt. Bei den meisten Antworten geht es nur darum, alle Dokumente zu durchlaufen und jedes einzeln zu speichern. Dies ist eine schlechte Idee, wenn Sie mehr als ein paar Dokumente haben, und der Vorgang wird sogar für eine von vielen Anfragen wiederholt.
MongoDB hat speziell einen
batchInsert()
Aufruf zum Einfügen mehrerer Dokumente, und dieser sollte vom nativen Mongodb-Treiber verwendet werden. Mongoose basiert auf diesem Treiber und unterstützt keine Batch-Einfügungen. Dies ist wahrscheinlich sinnvoll, da es sich um ein Objektdokumentmodellierungswerkzeug für MongoDB handeln soll.Lösung: Mongoose wird mit dem nativen MongoDB-Treiber geliefert. Sie können diesen Treiber verwenden, indem Sie ihn benötigen
require('mongoose/node_modules/mongodb')
(nicht sicher, aber Sie können den mongodb npm immer wieder installieren, wenn er nicht funktioniert, aber ich denke, er sollte es tun) und dann einen ordnungsgemäßen Vorgang ausführenbatchInsert
quelle
mongodb
Javascript-Treiber an.Neuere Versionen von MongoDB unterstützen Massenoperationen:
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).'); }
quelle
Hier ist ein anderer Weg ohne zusätzliche Bibliotheken (keine Fehlerprüfung enthalten)
function saveAll( callback ){ var count = 0; docs.forEach(function(doc){ doc.save(function(err){ count++; if( count == docs.length ){ callback(); } }); }); }
quelle
Sie können das von Mungo zurückgegebene Versprechen verwenden
save
,Promise
in Mungo gibt es nicht alle, aber Sie können die Funktion mit diesem Modul hinzufügen.Erstellen Sie ein Modul, das das Versprechen von Mungos bei allen verbessert.
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;
Dann verwenden Sie es mit Mungo:
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); })
quelle
Verwenden Sie die
insertMany
Funktion, um viele Dokumente einzufügen. Dies sendet nur eine Operation an den Server undMongoose
überprüft alle Dokumente, bevor der Mongo-Server erreicht wird. Standardmäßig wird dasMongoose
Element in der Reihenfolge eingefügt, in der es im Array vorhanden ist. Wenn Sie keine Reihenfolge einhalten können, stellen Sie einordered:false
.Wichtig - Fehlerbehandlung:
Wenn die
ordered:true
Validierung und Fehlerbehandlung in einer Gruppe erfolgt, schlägt alles fehl, wenn eine fehlschlägt.Wenn die
ordered:false
Validierung und Fehlerbehandlung einzeln erfolgt und der Betrieb fortgesetzt wird. Fehler werden in einer Reihe von Fehlern zurückgemeldet.quelle
Fügen Sie eine Datei mit dem Namen mongoHelper.js hinzu
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;
Dann müssen Sie in Ihrem Code ändern
var MongoClient = require("./mongoHelper.js");
Wenn es dann Zeit ist, den Anruf zu speichern (nachdem Sie die Sammlung verbunden und abgerufen haben)
MongoClient.saveAny(data, collection, function(){db.close();});
Sie können die Fehlerbehandlung an Ihre Bedürfnisse anpassen, den Fehler im Rückruf zurückgeben usw.
quelle
Dies ist eine alte Frage, die jedoch in den Google-Ergebnissen bei der Suche nach "Mungo-Einfügungsarray von Dokumenten" zuerst für mich auftauchte.
Es gibt zwei Optionen model.create () [mongoose] und model.collection.insert () [mongodb], die Sie verwenden können. Sehen Sie sich hier eine gründlichere Diskussion der Vor- und Nachteile der einzelnen Optionen an:
Mungo (Mongodb) Batch-Einsatz?
quelle
Hier ist ein Beispiel für die Verwendung von MongoDBs
Model.collection.insert()
direkt in Mongoose. Bitte beachten Sie, dass Sie, wenn Sie nicht so viele Dokumente haben, beispielsweise weniger als 100 Dokumente, den Massenvorgang von MongoDB nicht verwenden müssen ( siehe hier ).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 });
quelle