NightOwl
NightOwl

Reputation: 1089

strange Mongoose behaviour - document will not save into DB

In the following code, I try to populate my dev DB with some test data. I would like to first delete all documents and then add new test ones:

var mongoose = require('mongoose')
    , Plan = mongoose.model('Plan')
    , Async = require('async')

Async.series([
    function(callback){
        // delete all records
        Plan.find(function(err,docs){
            for (d in docs)
              Plan.remove(d, function(err) {
                  if (err) console.log("error removing records " + err)
              });
        });
        callback();
    },
    function(callback){
        var planArray = [
          {title: 'Plan A', body: 'Restaurant Financial Plan'},
          {title: 'Plan B', body: 'Coffeeshop Financial Plan'},
          {title: 'Plan C', body: 'bar Financial Plan'}
        ]

        var arrayLength = planArray.length;
        for (var i = 0; i < arrayLength; i++) {
          var p = new Plan(planArray[i])
          p.save(function(err, saved){
            if (err)
              {console.log("error creating fixture " + err)}
            else {
              console.log(saved)
            }
          })
        }
        callback();
    }
])

The interesting (strange) behaviour is this: - the code runs and removes all documents but does not add the new test ones. - no errors on the console, the console.log(saved) prints each new document to the console successfully. - if I remove the first Async function (delete all records) - then the new docs are saved into the DB.

a mongoose quirk or my misunderstanding of async flow..?

Upvotes: 1

Views: 400

Answers (3)

Neil Lunn
Neil Lunn

Reputation: 151092

There were a few problems. Firstly you have a for loop that is firing of async removes, but these were likely not completing before your first callback was called. Better to use Async.each instead.

Also there seems to be some function naming collision happening. So for a complete example of this see the following:

var mongoose = require('mongoose'),
    Async = require('async'),
    Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/test');

var planSchema = new Schema({
  title: String,
  body: String
});

var Plan = mongoose.model('Plan',planSchema);

Async.series([
  function(call1) {
    Plan.find(function(err,docs) {
      if (err)
        throw err;

      if ( docs.length > 0 ) {
        Async.each( docs, function(d, call2) {
          Plan.remove(d, function(err) {
            if (err)
              throw err;
            console.log( "deleting: " + d );
            call2();
          });
        });
      }
    });
    call1();
  },
  function(call3) {

    var planArray = [
      { title: 'Plan A', body: 'Plan A' },
      { title: 'Plan B', body: 'Plan B' }
    ];

    var arrayLength = planArray.length;

    for ( var i = 0; i < arrayLength; i++ ) {
      var p = new Plan(planArray[i]);
      p.save(function(err,saved) {
        if (err)
          throw err;

        console.log( "saving: " + saved );

      });

    }
    call3();
  }
]);

Upvotes: 2

Andrei Beziazychnyi
Andrei Beziazychnyi

Reputation: 2917

Second function starts execution after you call callback(), i. e. before find and remove calls. You have to wait until find and remove are done and the call callback(). Have a look at queue method from async: https://github.com/caolan/async#queue

Upvotes: 0

Jorge Aranda
Jorge Aranda

Reputation: 2080

My guess is the latter--a misunderstanding of async flow. Your callback on the first function is invoked before you finish finding and removing documents. So while you're still finding and removing them, you are already adding some more in the second function--but these will be found and removed by the first.

You need to call the first callback only after deleting all documents. Try putting an async.each within your Plan.find callback:

Async.series([
    function(callback){
        // delete all records
        Plan.find(function(err, docs){
            Async.each(
                docs, // your array
                function removeDoc(d, cb) { // iterator function
                    Plan.remove(d, function (err) {
                        if (err) console.log("error removing records " + err);
                        return cb();
                    });
                }, 
                callback // executed after the iterator is done
            );
    },
    ...

Incidentally, I believe Plan.remove({}, function(err){...}) deletes all documents--no need to iterate over each document unless of course you're doing something else.

Upvotes: 1

Related Questions