Saving multiple documents using Mongoose and doing something when the latter is saved

I want to save 8 objects to a MongoDB database using Mongoose. When the last document is saved, I want to inform (that is, send an event) that all documents have been saved.

The way I do it now is pretty messy (especially for the ever-increasing number of documents I want to keep).

Here is how I do it now (only for 4 people for this example). Is there a cleaner way you can recommend?

person1.save(function(err, result){ if (err) console.log(err); else{ person2.save(function(err, result){ if (err) console.log(err); else{ person3.save(function(err, result){ if (err) console.log(err); else{ person4.save(function(err, result){ if (err) console.log(err); else{ done(); } }); } }); } }); } }); 
+5
source share
5 answers

A useful library for coordinating asynchronous operations is async . In your case, the code will look something like this:

 var people = [ person1, person2, person3, person4, ... ]; async.eachSeries(people, function(person, asyncdone) { person.save(asyncdone); }, function(err) { if (err) return console.log(err); done(); // or `done(err)` if you want the pass the error up }); 
+12
source

Using promises and Array.map ()

 const userPromises = persons.map(user => { return new Promise((resolve, reject) => { person.save((error, result) => { if (error) { reject(error) } resolve(result); }) }) }); Promise.all(userPromises).then((results) => { //yay! //results = [first, second, etc...] }, (error) => { //nay! }) 
+3
source

I would recommend having an array and saving with iteration. Will have the same performance, but the code will be cleaner.

You may have

 var Person = mongoose.model('Person'); var people = []; people[0] = new Person({id: 'someid'}); people[0].set('name', 'Mario'); people[1] = new Person({id: 'someid'}); people[1].set('name', 'Mario'); people[2] = new Person({id: 'someid'}); people[2].set('name', 'Mario'); var errors = []; for(person in people){ people[person].save(function(err, done){ if(err) errors.push(err); if (person === people.length){ yourCallbackFunction(errors){ if (errors.length!=0) console.log(errors); //yourcode here }; } }); } 
+2
source

I would use Underscore Every to iterate over the People array. This will cause your code to become cleaner and help to avoid the boomerang effect that you encountered with your code.

From the documentation :

.each (list, iteratee, [context]) Alias: forEach

Iterate over a list of items, each of which leads to an iterative function. An iterator is bound to a context object, if passed. Each call to iteratee is called with three arguments: (element, index, list). If the list is a JavaScript object, iteratee arguments will be (value, key, list). Returns a list of conversations.

For instance:

 var people = [person1, person2]; var length = people.length; var hasError = false; var doSomething = function() { console.log('I'm done'); } var doSomethingElse = function() { console.log('There was an error'); } _.each(people, function(person, i) { if (!hasError) { person.save(function(err, result) { if (err) { console.log(err); hasError = true; } ); if (i === length) { doSomething(); } } else { // There was an error doSomethingElse(); } }); 
0
source

The best way is to use async waterfall . Part of the code snippet may look like the one shown below. Please refer to the link above. This violates the asynchronous nature and transforms into a process one by one (if I'm not mistaken).

  waterfall([ function(callback){ callback(null, 'one', 'two'); }, function(arg1, arg2, callback){ callback(null, 'three'); }, function(arg1, callback){ // arg1 now equals 'three' callback(null, 'done'); } ], function (err, result) { // result now equals 'done' }); 
0
source

All Articles