Inserto in lotti di mangusta (mongodb)?


114

Non v3.6 + Mongoose inserti in lotti di sostegno ora? Ho cercato per alcuni minuti, ma qualsiasi cosa che corrisponda a questa query ha un paio di anni e la risposta è stata un no inequivocabile.

Modificare:

Per riferimento futuro, la risposta è usare Model.create(). create()accetta un array come primo argomento, quindi puoi passare i tuoi documenti da inserire come array.

Vedere la documentazione di Model.create ()


Vedi questa risposta a una domanda precedente.
JohnnyHK

Grazie. Questo è quello che ho trovato dopo aver postato.
Geuis

@Geuis per favore aggiungi la tua modifica come risposta e accettala per risolvere la tua domanda.
Filip Dupanović


Model.create () è lento e se stai considerando di inserire un numero enorme di documenti, è meglio adottare invece questo approccio .
Lucio Paiva

Risposte:


162

Model.create () vs Model.collection.insert (): un approccio più veloce

Model.create()è un cattivo modo di fare inserti se hai a che fare con una massa molto grande. Sarà molto lento . In tal caso dovresti usare Model.collection.insert, che funziona molto meglio . A seconda delle dimensioni della massa, si Model.create()bloccherà anche! Ho provato con un milione di documenti, senza fortuna. L'utilizzo Model.collection.insertha richiesto solo pochi secondi.

Model.collection.insert(docs, options, callback)
  • docs è la matrice di documenti da inserire;
  • optionsè un oggetto di configurazione opzionale: vedere la documentazione
  • callback(err, docs)verrà chiamato dopo che tutti i documenti sono stati salvati o si è verificato un errore. In caso di successo, i documenti sono la matrice di documenti persistenti.

Come l'autore di Mongoose sottolinea qui , questo metodo ignorerà qualsiasi procedura di convalida e accederà direttamente al driver Mongo. È un compromesso che devi fare poiché stai gestendo una grande quantità di dati, altrimenti non saresti in grado di inserirlo affatto nel tuo database (ricorda che stiamo parlando di centinaia di migliaia di documenti qui).

Un semplice esempio

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

Aggiornamento 2019-06-22 : sebbene insert()possa ancora essere utilizzato correttamente , è stato deprecato a favore di insertMany(). I parametri sono esattamente gli stessi, quindi puoi usarlo come sostituto drop-in e tutto dovrebbe funzionare bene (beh, il valore di ritorno è leggermente diverso, ma probabilmente non lo stai usando comunque).

Riferimento



Per favore fai un esempio con Mangusta.
Steve K

15
Dato che Model.collectionpassa direttamente attraverso il driver Mongo, perdi tutta la roba pulita della mangusta inclusa la convalida e gli hook. Solo qualcosa da tenere a mente. Model.createperde gli hook, ma passa ancora attraverso la convalida. Se vuoi tutto, devi iterare enew MyModel()
Pier-Luc Gendreau

1
@ Pier-LucGendreau Hai assolutamente ragione, ma è un compromesso che devi fare una volta che inizi a gestire una quantità enorme di dati.
Lucio Paiva

1
Attenzione ai nuovi lettori: "Modificato nella versione 2.6: L'inserto () restituisce un oggetto che contiene lo stato dell'operazione". Niente più documenti.
Mark Ni

117

Mongoose 4.4.0 ora supporta l'inserimento in blocco

Mongoose 4.4.0 introduce --true-- inserto in blocco con il metodo del modello .insertMany(). È molto più veloce che eseguire il loop .create()o fornirgli un array.

Uso:

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

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

O

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

Puoi seguirlo su:


2
Al momento, questo metodo non supporta le opzioni.
Amri

Grazie per la risposta. Qualche idea su quale dovrebbe essere l'analisi dei rawDocuments? L'ho provato con una serie di oggetti Json e tutto ciò che ha inserito erano solo i loro ID. :(
Ondrej Tokar

4
In che modo è diverso da bulkWrite? Vedi qui: stackoverflow.com/questions/38742475/…
Ondrej Tokar

insertMany non funziona per me. Ho un fatal error allocation failed. Ma se uso collection.insert Funziona perfettamente.
John

Funzionerebbe con le cose extra fornite dallo schema di mangusta? ex questo aggiungerà i dati se non esiste una datadateCreated : { type: Date, default: Date.now },
jack vuoto

22

In effetti, puoi usare il metodo "crea" di Mongoose, può contenere un array di documenti, vedi questo esempio:

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

La funzione di callback contiene i documenti inseriti. Non sai sempre quanti elementi devono essere inseriti (lunghezza argomento fissa come sopra) in modo da poterli scorrere in ciclo:

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

Aggiornamento: una soluzione migliore

Una soluzione migliore sarebbe usare al Candy.collection.insert()posto di Candy.create()- usato nell'esempio sopra - perché è più veloce ( create()chiama Model.save()su ogni elemento quindi è più lento).

Consulta la documentazione di Mongo per maggiori informazioni: http://docs.mongodb.org/manual/reference/method/db.collection.insert/

(grazie ad arcseldon per averlo sottolineato)


groups.google.com/forum/#!topic/mongoose-orm/IkPmvcd0kds - A seconda di ciò che desideri, il link ha un'opzione migliore.
arcseldon

Non intendi {type:'jellybean'}invece di {type:'jelly bean'}? Btw. che tipi strani sono quelli? Fanno parte dell'API Mongoose?
Steve K

2
Bene, allora questa è una cattiva scelta di denominazione, poiché di typesolito è riservata in Mongoose per denominare l'ADT di un oggetto di database.
Steve K

2
@sirbenbenji l'ho cambiato, ma era un esempio presente anche nella documentazione ufficiale. Non era necessario downvote per questo credo.
benske

1
Affrontando la proprietà .collection stai aggirando Mongoose (convalida, metodi 'pre' ...)
Derek

4

È possibile eseguire l'inserimento in blocco utilizzando la shell mongoDB utilizzando l'inserimento dei valori in un array.

db.collection.insert([{values},{values},{values},{values}]);

c'è un modo in mangusta per l'inserimento di massa?
SUNDARRAJAN K

1
YourModel.collection.insert()
Bill Dami

Indirizzando la proprietà .collection stai aggirando Mongoose (convalida, metodi 'pre' ...)
Derek

Questa non è mangusta e la collection.insertrisposta grezza è stata data poche settimane prima di questa risposta e spiegata in modo molto più dettagliato.
Dan Dascalescu

4

È possibile eseguire l'inserimento in blocco utilizzando mangusta, come risposta con il punteggio più alto. Ma l'esempio non può funzionare, dovrebbe essere:

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

Non utilizzare un'istanza dello schema per l'inserimento in blocco, dovresti utilizzare un oggetto mappa semplice.


La prima risposta non è sbagliata, ha solo convalida
Luca Steeb

1
Affrontando la proprietà .collection stai bypassando Mongoose (convalida, metodi 'pre' ...)
Derek

4

Qui ci sono entrambi i modi per salvare i dati con insertMany e save

1) Mongoose salva una serie di documenti insertManyin blocco

/* 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) Mongoose salva la serie di documenti con .save()

Questi documenti salveranno parallelamente.

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

3

Sembra che usando la mangusta ci sia un limite di più di 1000 documenti, quando si usa

Potato.collection.insert(potatoBag, onInsert);

Puoi usare:

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

Ma questo è quasi il doppio più veloce quando si esegue il test con 10000 documenti:

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

1
Indirizzando la proprietà .collection stai aggirando Mongoose (convalida, metodi 'pre' ...)
Derek

0

Condivisione del codice di lavoro e pertinente dal nostro progetto:

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

La .insertManysoluzione era già stata data (e spiegata) in questa risposta del 2016 .
Dan Dascalescu
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.