Mongoose.js instance.save() callback not firing

2019-01-07 16:33发布

问题:

var mongo = require('mongoose');
var connection = mongo.createConnection('mongodb://127.0.0.1/test');

connection.on("error", function(errorObject){
  console.log(errorObject); 
  console.log('ONERROR');
});

var Schema = mongo.Schema;
var BookSchema = new Schema({ title : {type : String, index : {unique : true}}});
var BookModel = mongo.model('abook', BookSchema);
var b = new BookModel({title : 'aaaaaa'});

b.save( function(e){ 
  if(e){
    console.log('error')
  }else{
    console.log('no error')
}});

Neither the 'error', or 'no error' are printed to the terminal. What's more the connection.on 'error' doesn't seem to fire either. I have confirmed that MongoDb is running.

回答1:

this is a case where you are adding the model to the global mongoose object but opening a separate connection mongo.createConnection() that the models are not part of. Since the model has no connection it cannot save to the db.

this is solved either by connecting to mongo on the global mongoose connection:

var connection = mongo.createConnection('mongodb://127.0.0.1/test');
// becomes
var connection = mongo.connect('mongodb://127.0.0.1/test');

or by adding your models to your separate connection:

var BookModel = mongo.model('abook', BookSchema);
// becomes
var BookModel = connection.model('abook', BookSchema);


回答2:

The posted answer does not solve the problem. Unfortunately, I cannot just upgrade my database, so that is not a solution either for me. But here I found a solution to this problem: https://github.com/Automattic/mongoose/issues/4064

Just use .$__save instead of .save as shown:

var b = new BookModel({title : 'aaaaaa'});

b.$__save({}, function(e){ 
  if(e){
    console.log('error')
    // callback will show if e exists
  }else{
    console.log('no error')
    // callback will show 'no error'
}});


回答3:

I really like Aaron's answer, and thanks to him I am now on my way to fixing the issue... although I'm not there yet! Here is my particular issue:

I want to have my schema and models defined in separate files, so I can reuse them from project to project. So as an example I have a file named W8DBItem.js as follows:

var mongoose = require('mongoose');
var itemSchema = new mongoose.Schema({ name: {type: String, required: true}});
module.exports = mongoose.model('W8DBItem', itemSchema);

In my program file I do this this:

var mongoose = require('mongoose');
var W8DBItem = require('../w8/W8DBItem.js'); 
var dbURL ='mongodb://localhost:27017/default';
var mongoOptions = { useNewUrlParser: true, bufferCommands: false }
mongoose.connect(dbURL, mongoOptions);

var db = mongoose.connection;

// DEAL WITH CONNECTION ERROR
db.on('error', console.error.bind(console, 'connection error:'));

// PREP DATA
var aWeight = { name: "My Test Name" };
var newWeightItem = W8DBItem(aWeight);

// CONNECTION ESTABLISHED
db.once('open', function() {
    console.log("Here 1")

    // TRY TO SAVE
   newWeightItem.save(function (err, newWeightItem) {
    if (err) { 
        console.log("Here 2");
        console.log(err);
    }
    else {
        console.log("Here 3");
        console.log(newWeightItem);
    }
  });
});

When I run this program I get "Here 1" but never "Here 2" or "Here 3" in the console.

From Aaron's post I get that the W8DBItem object has no associated (and open) connections, but I am not sure how to go about fixing things. I could connect to the DB in the W8DBItem.js file, but I really don't like hard-coding the server info with the objects - I want these objects to be used in different files, and perhaps with different servers.

Ideas and suggestions are much appreciated!

[EDIT: SOLUTION FOUND!!!]

Instead of exporting my mongoose.model from my object file, I am only exporting the schema:

var mongoose = require('mongoose');
var itemSchema = new mongoose.Schema({name: {type: String, required: true}});
module.exports = itemSchema;

In my program files I then do this:

var itemSchema = require('../w8/W8DBItemSchema.js'); 
...

var W8DBItem = db.model('W8DBItem', itemSchema);
var newWeightItem = W8DBItem(aWeight);
...

Works like a charm. I hope this helps someone!