Mungo (Mongodb) Batch-Einsatz?

114

Does Mongoose v3.6 + unterstützt Batch - Einsätze jetzt? Ich habe ein paar Minuten gesucht, aber alles, was zu dieser Abfrage passt, ist ein paar Jahre alt und die Antwort war ein eindeutiges Nein.

Bearbeiten:

Zum späteren Nachschlagen ist die Antwort zu verwenden Model.create(). create()Akzeptiert ein Array als erstes Argument, sodass Sie Ihre Dokumente zum Einfügen als Array übergeben können.

Siehe Dokumentation zu Model.create ()

Geuis
quelle
Siehe diese Antwort auf eine vorherige Frage.
JohnnyHK
Vielen Dank. Das habe ich nach dem Posten gefunden.
Geuis
@Geuis Bitte fügen Sie Ihre Bearbeitung als Antwort hinzu und akzeptieren Sie sie, um Ihre Frage zu lösen.
Filip Dupanović
Model.create () ist langsam und wenn Sie eine große Anzahl von Dokumenten einfügen möchten, ist es besser, stattdessen diesen Ansatz zu wählen.
Lucio Paiva

Antworten:

162

Model.create () vs Model.collection.insert (): ein schnellerer Ansatz

Model.create()ist ein schlechter Weg, um Einfügungen zu machen, wenn Sie mit einer sehr großen Masse zu tun haben. Es wird sehr langsam sein . In diesem Fall sollten Sie verwenden Model.collection.insert, was viel besser funktioniert . Abhängig von der Größe der Masse Model.create()wird sogar abstürzen! Versucht mit einer Million Dokumenten, kein Glück. Die Benutzung Model.collection.insertdauerte nur wenige Sekunden.

Model.collection.insert(docs, options, callback)
  • docs ist das Array der einzufügenden Dokumente;
  • optionsist ein optionales Konfigurationsobjekt - siehe Dokumentation
  • callback(err, docs)wird aufgerufen, nachdem alle Dokumente gespeichert wurden oder ein Fehler auftritt. Bei Erfolg ist docs das Array von persistierten Dokumenten.

Wie der Autor von Mongoose hier betont, umgeht diese Methode alle Validierungsverfahren und greift direkt auf den Mongo-Treiber zu. Es ist ein Kompromiss, den Sie eingehen müssen, da Sie eine große Datenmenge verarbeiten, da Sie sie sonst überhaupt nicht in Ihre Datenbank einfügen könnten (denken Sie daran, dass es sich hier um Hunderttausende von Dokumenten handelt).

Ein einfaches Beispiel

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 : Obwohl es insert()immer noch einwandfrei verwendet werden kann, wurde es zugunsten von abgelehnt insertMany(). Die Parameter sind genau gleich, Sie können sie also einfach als Ersatz verwenden und alles sollte einwandfrei funktionieren (der Rückgabewert ist etwas anders, aber Sie verwenden ihn wahrscheinlich trotzdem nicht).

Referenz

Lucio Paiva
quelle
Bitte geben Sie ein Beispiel mit Mungo.
Steve K
15
Da es Model.collectiondirekt durch den Mongo-Treiber geht, verlieren Sie alle ordentlichen Mungo-Sachen, einschließlich Validierung und Haken. Nur etwas zu beachten. Model.createverliert die Haken, durchläuft aber noch die Validierung. Wenn Sie alles wollen, müssen Sie iterieren undnew MyModel()
Pier-Luc Gendreau
1
@ Pier-LucGendreau Sie haben absolut Recht, aber es ist ein Kompromiss, den Sie eingehen müssen, wenn Sie anfangen, mit einer riesigen Datenmenge umzugehen.
Lucio Paiva
1
Seien Sie vorsichtig für neue Leser: "In Version 2.6 geändert: Die Einfügung () gibt ein Objekt zurück, das den Status der Operation enthält". Keine Dokumente mehr.
Mark Ni
117

Mongoose 4.4.0 unterstützt jetzt Bulk Insert

Mongoose 4.4.0 führt --true-- Bulk Insert mit der Modellmethode ein .insertMany(). Es ist viel schneller als eine Schleife .create()oder ein Array.

Verwendung:

var rawDocuments = [/* ... */];

Book.insertMany(rawDocuments)
    .then(function(mongooseDocuments) {
         /* ... */
    })
    .catch(function(err) {
        /* Error handling */
    });

Oder

Book.insertMany(rawDocuments, function (err, mongooseDocuments) { /* Your callback function... */ });

Sie können es verfolgen auf:

Derek
quelle
2
Derzeit unterstützt diese Methode keine Optionen.
Amri
Danke für die Antwort. Irgendeine Idee, welche Analyse der rawDocuments vorhanden sein sollte? Ich habe es mit einem Array von Json-Objekten versucht und alles, was es eingefügt hat, waren nur ihre IDs. :(
Ondrej Tokar
4
Wie unterscheidet sich das von bulkWrite? Siehe hier: stackoverflow.com/questions/38742475/…
Ondrej Tokar
insertMany funktioniert bei mir nicht. Ich habe eine fatal error allocation failed. Aber wenn ich collection.insert benutze, funktioniert es perfekt.
John
Würde dies mit den zusätzlichen Dingen funktionieren, die das Mungo-Schema bietet? ex wird dies die Daten hinzufügen, wenn kein Datum existiertdateCreated : { type: Date, default: Date.now },
Jack Blank
22

In der Tat können Sie die "create" -Methode von Mongoose verwenden. Sie kann eine Reihe von Dokumenten enthalten. Siehe dieses Beispiel:

Candy.create({ candy: 'jelly bean' }, { candy: 'snickers' }, function (err, jellybean, snickers) {
});

Die Rückruffunktion enthält die eingefügten Dokumente. Sie wissen nicht immer, wie viele Elemente eingefügt werden müssen (feste Argumentlänge wie oben), damit Sie sie durchlaufen können:

var insertedDocs = [];
for (var i=1; i<arguments.length; ++i) {
    insertedDocs.push(arguments[i]);
}

Update: Eine bessere Lösung

Eine bessere Lösung wäre, Candy.collection.insert()anstatt Candy.create()- wie im obigen Beispiel verwendet - zu verwenden, weil es schneller ist ( create()ruft Model.save()jedes Element auf, damit es langsamer ist).

Weitere Informationen finden Sie in der Mongo-Dokumentation: http://docs.mongodb.org/manual/reference/method/db.collection.insert/

(danke an arcseldon für den Hinweis)

Benske
quelle
groups.google.com/forum/#!topic/mongoose-orm/IkPmvcd0kds - Je nachdem, was Sie möchten, bietet der Link eine bessere Option.
Arcseldon
Meinst du nicht {type:'jellybean'}statt {type:'jelly bean'}? Übrigens. Was für seltsame Typen sind das? Sind sie Teil der Mongoose API?
Steve K
2
Nun, das ist dann eine schlechte Namenswahl, da sie typein Mongoose normalerweise für die Bezeichnung der ADT eines Datenbankobjekts reserviert ist.
Steve K
2
@sirbenbenji Ich habe es geändert, aber es war ein Beispiel, das auch in der offiziellen Dokumentation enthalten war. Ich denke, es war nicht notwendig, dafür zu stimmen.
Benske
1
Indem Sie die .collection-Eigenschaft adressieren, umgehen Sie Mongoose (Validierung, 'pre'-Methoden ...)
Derek
4

Sie können eine Masseneinfügung mithilfe der mongoDB-Shell durchführen, indem Sie die Werte in ein Array einfügen.

db.collection.insert([{values},{values},{values},{values}]);
SUNDARRAJAN K.
quelle
Gibt es in Mungo einen Weg für Masseneinsatz?
SUNDARRAJAN K
1
YourModel.collection.insert()
Bill Dami
Indem Sie die .collection-Eigenschaft adressieren, umgehen Sie Mongoose (Validierung, 'pre'-Methoden ...)
Derek
Dies ist kein Mungo, und die rohe collection.insertAntwort wurde einige Wochen vor dieser Antwort gegeben und viel detaillierter erklärt.
Dan Dascalescu
4

Sie können Masseneinfügungen mit Mungo als Antwort mit der höchsten Punktzahl durchführen. Aber das Beispiel kann nicht funktionieren, es sollte sein:

/* 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);
    }
}

Verwenden Sie keine Schemainstanz für die Masseneinfügung, sondern verwenden Sie ein einfaches Kartenobjekt.

user2582680
quelle
Die erste Antwort ist nicht falsch, sie hat nur eine Bestätigung
Luca Steeb
1
Indem Sie die .collection-Eigenschaft adressieren, umgehen Sie Mongoose (Validierung, 'pre'-Methoden ...)
Derek
4

Hier sind beide Möglichkeiten zum Speichern von Daten mit insertMany und zum Speichern

1) Mungo speichert eine Reihe von Dokumenten insertManyin großen Mengen

/* 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});
    });
})

2) Mungo speichern Array von Dokumenten mit .save()

Diese Dokumente werden parallel gespeichert.

/* 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});
        })
    })
})
Arpit
quelle
3

Es scheint, dass bei der Verwendung von Mungo die Verwendung von mehr als 1000 Dokumenten begrenzt ist

Potato.collection.insert(potatoBag, onInsert);

Sie können verwenden:

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)
      });
});

Beim Testen mit 10000 Dokumenten ist dies jedoch fast doppelt so schnell:

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);
    });
}
ddennis
quelle
1
Indem Sie die .collection-Eigenschaft adressieren, umgehen Sie Mongoose (Validierung, 'pre'-Methoden ...)
Derek
0

Teilen von funktionierendem und relevantem Code aus unserem Projekt:

//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);
    });
Zameer
quelle
Die .insertManyLösung wurde bereits in dieser Antwort von 2016 angegeben (und erläutert) .
Dan Dascalescu