简体   繁体   中英

Callback recursive insertion Mongo with Node.js

i am doing an API with Node.js and MongoDB (Mongoose.js). And i making a "installation" script to populate the database with some example data, like users and other stuff.

The problem is when i try to add a recursive inserts.

I add 999 documents to one collection (Father), and 12 documents for each Father document in another collections (Sons).

The father collection has 999 documents. But the sons collection has only 1188 when i expect 11988 documents in Sons collection.

The models are correct. I have a lot of unit tests that validate the operation of these.

This is my code:

var mongoose = require('mongoose');
var conf = require('../config/dbConfig');
var fatherDb = require('../model/father');
var sonsDb = require('../model/son');
var db_lnk = conf.mongoSrv();
global.db = (global.db ? global.db : mongoose.createConnection(db_lnk));

function addFather(idSome, idOther){
    console.log("Adding Fathers");
    fatherDb.count({active:true}, function(err,count){
        if(!err){
            var max = (999-count);
            for(i=0; i<max; i++){
                var father = new fatherDb({
                    "name":"Father "  + (i+1),
                    "createdBy" : "55ad5f224f350c123b8e2bda",
                    "modifyBy" : "55ad5f224f350c123b8e2bda",
                    "active" : true,
                    "_some" : idSome,
                    "_other" : idOther,
                    "__v" : 0
                });
                father.save(function(err, data){
                    console.log("Adding 12 Sons to Father # " + i);
                    var idFather = data._id;
                    for (var x = 1; x < 13; x++) {
                        var son = new sonsDb({
                            "name": "Son " + x,
                            "position": x,
                            "createdBy": "55ad5f442f350c431b8e2bda",
                            "modifyBy": "55ad5f442f350c431b8e2bda",
                            "active": true,
                            "_father": idFather,
                            "__v": 0
                        });
                        son.save(function (err) {
                            console.log("Adding Son " + x);
                            if(i == max) {
                                endInstall();
                            }
                        });
                    }
                });
            }
        }else{
            console.log("Error");
            endInstall();
        }
    });
}

function endInstall(){
    console.log("Ending Installation");
    process.exit();
}

addFather('SOMEid','OtherId');

.save() is an asynchronous function, so the for loop will continue to run them before they've been completed. That way i will reach max sooner than you expected.

In other words, i reaches max after all the father.save have been fired, not done, and son.save will exec endInstall() prematurely.

async is a library to deal with this kind of situations. If you want to continue with counters, take a look at the times method .

Something like:

// generate max fathers
async.times(max, function(n, next_father){
  var father = ...
  father.save(function(err){
    // generate 12 sons
    async.times(12, function(m, next_son){
      var son = ...
      son.save(function(err){
        next_son(err);
      });
    }, function(err, sons){
      next_father(err);
    });
  });
}, function(err, fathers) {
  // it's done
});

That way you can be sure that everything is done.

This bit here is calling your endInstall method before everything is done processing.

 son.save(function (err) {
    console.log("Adding Son " + x);
    if(i == max) {
      endInstall();
     }
    });
 }

Instead of trying to use for loops use the async library.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM