Wstawianie partii Mongoose (mongodb)?


114

Czy Mongoose v3.6 + obsługuje teraz wstawianie wsadowe? Szukałem przez kilka minut, ale wszystko, co pasuje do tego zapytania, ma kilka lat, a odpowiedź była jednoznaczna nie.

Edytować:

Na przyszłość odpowiedzią jest użycie Model.create(). create()akceptuje tablicę jako pierwszy argument, więc możesz przekazać swoje dokumenty do wstawienia jako tablicę.

Zobacz dokumentację Model.create ()


Zobacz tę odpowiedź na poprzednie pytanie.
— JohnnyHK

Dzięki. To właśnie znalazłem po opublikowaniu.
— Geuis

@Geuis, dodaj swoją zmianę jako odpowiedź i zaakceptuj ją, aby rozwiązać swoje pytanie.
— Filip Dupanović


Model.create () jest powolny i jeśli rozważasz wstawianie ogromnej liczby dokumentów, lepiej zamiast tego zastosować to podejście .
— Lucio Paiva

Odpowiedzi:


162

Model.create () vs Model.collection.insert (): szybsze podejście

Model.create()to zły sposób wykonywania wkładek, jeśli masz do czynienia z bardzo dużą masą. Będzie to bardzo powolne . W takim przypadku powinieneś użyć Model.collection.insert, który działa znacznie lepiej . W zależności od wielkości masy Model.create()nawet się rozbije! Próbowałem z milionem dokumentów, bez powodzenia. Korzystanie z Model.collection.insertniego zajęło zaledwie kilka sekund.

Model.collection.insert(docs, options, callback)
  • docs jest tablicą dokumentów do wstawienia;
  • optionsjest opcjonalnym obiektem konfiguracyjnym - zobacz dokumentację
  • callback(err, docs)zostanie wywołana po zapisaniu wszystkich dokumentów lub wystąpieniu błędu. W przypadku sukcesu, docs to szereg utrwalonych dokumentów.

Jako autor Mongoose Punkty się tutaj metoda ta ominie wszelkich procedur walidacji i dostępu kierowca Mongo bezpośrednio. Jest to kompromis, który musisz zrobić, ponieważ obsługujesz dużą ilość danych, w przeciwnym razie nie byłbyś w stanie w ogóle wstawić ich do bazy danych (pamiętaj, że mówimy tutaj o setkach tysięcy dokumentów).

Prosty przykład

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

Aktualizacja 2019-06-22 : chociaż insert()nadal można go używać dobrze, został wycofany na korzyść insertMany(). Parametry są dokładnie takie same, więc możesz go po prostu użyć jako zamiennika typu drop-in i wszystko powinno działać dobrze (cóż, wartość zwracana jest nieco inna, ale prawdopodobnie i tak jej nie używasz).

Odniesienie



Proszę podać przykład z Mongoose.
— Steve K

15
Od Model.collection przechodzi bezpośrednio przez sterownik Mongo, tracisz wszystkie zgrabne rzeczy, w tym sprawdzanie poprawności i haczyki. Tylko coś do zapamiętania. Model.createtraci haczyki, ale nadal przechodzi przez weryfikację. Jeśli chcesz tego wszystkiego, musisz iterować inew MyModel()
— Pier-Luc Gendreau

1
@ Pier-LucGendreau Masz całkowitą rację, ale jest to kompromis, który musisz zrobić, gdy zaczniesz zajmować się ogromną ilością danych.
— Lucio Paiva,

1
Uważaj na nowych czytelników: „Zmieniono w wersji 2.6: funkcja insert () zwraca obiekt, który zawiera stan operacji”. Żadnych więcej dokumentów.
— Mark Ni

117

Mongoose 4.4.0 obsługuje teraz wstawianie zbiorcze

Mongoose 4.4.0 wprowadza --true-- zbiorcze wstawianie z metodą modelu .insertMany(). Jest to znacznie szybsze niż zapętlanie .create()lub udostępnianie tablicy.

Stosowanie:

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

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

Lub

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

Możesz go śledzić na:


2
W tej chwili ta metoda nie obsługuje opcji.
— Amri,

Dziękuję za Twoją odpowiedź. Masz pojęcie, jakie powinno być analizowanie surowych dokumentów? Wypróbowałem to z tablicą obiektów Json i wszystko, co wstawił, to tylko ich identyfikatory. :(
— Ondrej Tokar

4
Czym się to różni od bulkWrite? Zobacz tutaj: stackoverflow.com/questions/38742475/…
— Ondrej Tokar

insertMany nie działa dla mnie. Mam fatal error allocation failed. Ale jeśli używam collection.insert Działa idealnie.
— John

Czy to zadziała z dodatkowymi rzeczami, które zapewnia schemat Mangusta? ex doda dane, jeśli nie istniejedateCreated : { type: Date, default: Date.now },
— gniazdo puste

22

Rzeczywiście, możesz użyć metody „tworzenia” Mongoose, może ona zawierać tablicę dokumentów, zobacz ten przykład:

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

Funkcja wywołania zwrotnego zawiera wstawione dokumenty. Nie zawsze wiesz, ile elementów należy wstawić (stała długość argumentów, jak powyżej), więc możesz je przeglądać w pętli:

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

Aktualizacja: lepsze rozwiązanie

Lepszym rozwiązaniem byłoby użycie Candy.collection.insert()zamiast Candy.create()- użyte w powyższym przykładzie - ponieważ jest szybsze ( create()wywołuje Model.save()każdy element, więc jest wolniejszy).

Więcej informacji można znaleźć w dokumentacji Mongo: http://docs.mongodb.org/manual/reference/method/db.collection.insert/

(dzięki arcseldonowi za wskazanie tego)


groups.google.com/forum/#!topic/mongoose-orm/IkPmvcd0kds - w zależności od tego, co chcesz, link ma lepszą opcję.
— arcseldon

Czy nie masz na myśli {type:'jellybean'}zamiast {type:'jelly bean'}? Przy okazji. jakie to dziwne typy? Czy są częścią Mongoose API?
— Steve K

2
Cóż, to zły wybór nazewnictwa, ponieważ typejest zwykle zarezerwowany w Mongoose do określania ADT obiektu bazy danych.
— Steve K,

2
@sirbenbenji Zmieniłem to, ale był to przykład obecny również w oficjalnej dokumentacji. Myślę, że nie było potrzeby głosowania przeciw temu.
— benske

1
Poprzez zajęcie mienia .collection jesteś pominięciem Mongoose (walidacji, metody 'pre' ...)
— Derek

4

Możesz wykonać zbiorcze wstawianie przy użyciu powłoki mongoDB, wstawiając wartości do tablicy.

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

czy jest sposób w mangusta na wkład luzem?
— SUNDARRAJAN K

1
YourModel.collection.insert()
— Bill Dami

Adresując właściwość .collection, omijasz Mongoose (sprawdzanie poprawności, metody `` pre '' ...)
— Derek

To nie jest mangusta, a surowa collection.insertodpowiedź została udzielona kilka tygodni przed tą odpowiedzią i wyjaśniona znacznie bardziej szczegółowo.
— Dan Dascalescu

4

Możesz wykonać zbiorcze wstawianie za pomocą mangusty, jako odpowiedzi o najwyższym wyniku. Ale przykład nie może działać, powinien być:

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

Nie używaj instancji schematu do wstawiania zbiorczego, powinieneś użyć zwykłego obiektu mapy.


Pierwsza odpowiedź nie jest zła, ma po prostu walidację
— Luca Steeb

1
Adresując właściwość .collection, omijasz Mongoose (sprawdzanie poprawności, metody 'pre' ...)
— Derek

4

Oto oba sposoby zapisywania danych za pomocą insertMany i save

1) Mongoose zapisuje insertManymasowo szereg dokumentów

/* 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 zapisuje tablicę dokumentów w formacie .save()

Dokumenty te będą zapisywać się równolegle.

/* 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

Wygląda na to, że przy używaniu mangusty istnieje limit ponad 1000 dokumentów

Potato.collection.insert(potatoBag, onInsert);

Możesz użyć:

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

Ale jest to prawie dwa razy szybsze w przypadku testowania na 10000 dokumentów:

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
Adresując właściwość .collection, omijasz Mongoose (sprawdzanie poprawności, metody `` pre '' ...)
— Derek

0

Udostępnianie działającego i odpowiedniego kodu z naszego projektu:

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

.insertManyRozwiązanie zostało już podane (i wyjaśnić), w tym 2016 odpowiedzi .
— Dan Dascalescu
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.