Jared Tomaszewski
Jared Tomaszewski

Reputation: 803

Mongoose doesn't save data to the MongoDB


Below is an object literal I am trying to save to MongoDB. It is defined within the app.js file which is an Express server. As the object is hardcoded within the server, my assumption was that a new copy would be saved to the DB every time I run the server, or at the very least the document would be saved once, and overridden or left unchanged upon detection that the new document is identical to the one saved on the last server run. To my astonishment, not only no copies are created within the MongoDB, but the document is not saved at all. However, the 'news' collection has been created, as verified with mongo shell 'show collections'. Also, I am not getting any error in the callback function. I also tried the Model.create(doc, fn) within my Express '/news' route, but this also doesn't work (the doc should be saved every time the '/news' route is called by the client, but it isn't). What am I missing?
Please, read my annotations marked with "<-" to see what other problems or unexpected behaviour I encounter. I will be very grateful if you could address those as well in your answer.

var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path')
  , fs = require('fs');

// Defining connection to the database:
var mongoose = require('mongoose').
    connect("mongodb://localhost:27017/my-test-db"),
    db = mongoose.connection;
var Schema = mongoose.Schema;
var ObjectID = Schema.ObjectId;
// Setting up the debug flag:
mongoose.set('debug, true');
// Logging connection:
db
  .on('error', console.error.bind(console, 'DB connection error.'))
  .once('open', console.log.bind(console, 'DB Connection established.'));

// Defining MongoDB schemas:
var usr = new Schema({
    first: String,
    last: String
});
var newsSchema = new Schema({
    headline: String,
    bd: String,
    imgURI: String,
    imgThumbURI: String,
    imgCaption: String,
    addedOn: Date,
    addedBy: {
        type: ObjectID,
        ref: 'usr'
    }
// On user action 'save' populate the addedOn and addedBy fields before the news article is actually saved to the DB:
newsSchema.pre('save', function(next){
    if( !this.addedOn ) this.addedOn = new Date();
    if( !this.addedBy ) this.addedBy = {first: "admin", last: "admin"};
});
// Indexing important fields:
usr.index({last: 1});
newsSchema.index({headline: 1});
//Adding the News model:
var News = mongoose.model('news', newsSchema);

var nws1 = new News({
    headline: "Test news Headline",
    bd: "Test news body. Test news body. Test news body. Test news body. Test news body. ",
    imgURI: encodeURI("images/news/img.jpg"),
    imgThumbURI: encodeURI("images/news/thumbs/img.jpg"),
    imgCaption: "Test news image caption.",
    addedOn: new Date(),
    addedBy: {first: "Admin", last: "Admin"}
});
nws1.save(function(err, news){
        if(err) return console.error("Error while saving data to MongoDB: " + err); // <- this gets executed when there's an error
        console.error(news); // <- this never gets logged, even if there's no error.
    });

var app = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.resolve(__dirname + '/public'));
app.set('view engine', 'html')
    .engine('html', function(path, options, fn){
        if('finction' == typeof options){
            fn = options, options = {};
        }
        fs.readFile(path, 'utf8', fn);
    });
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.session());

app.use(express.static(path.join(__dirname, 'public')));
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});

Thank you for your time
Best regards
Jared

Upvotes: 7

Views: 22682

Answers (3)

Chris Prince
Chris Prince

Reputation: 7574

My code was different, but my result was apparently the same: Apparently, I wasn't saving to Mongo despite the .save call. HOWEVER, the save was actually taking place, I just didn't realize what some of the Mongoose parameters mean, and that it takes some liberties forming your collection name.

More specifically, when you use:

mongoose.model('MyModelName', invitationSchema);

to form your collection name, your model name gets converted to lower case and an "s" gets appended (if not there). See also http://samwize.com/2014/03/07/what-mongoose-never-explain-to-you-on-case-sentivity/

You can, if you want, bypass these collection naming conventions to some extent by using a collection name parameter when you create the schema. See http://mongoosejs.com/docs/guide.html#collection

Here's mine:

const modelName = "SharingInvitation";
const collectionName = modelName + "s";

const numberOfHoursBeforeExpiry = 24;

var expiryDate = new Date ();
expiryDate.setHours(expiryDate.getHours() + numberOfHoursBeforeExpiry);

var invitationSchema = new Schema({
    // _id: (ObjectId), // Uniquely identifies the invitation (autocreated by Mongo)

    // gives time/day that the invitation will expire
    expiry: { type: Date, default: expiryDate },

    // The user is being invited to share the following:
    owningUser: ObjectId, // The _id of a PSUserCredentials object.
    capabilities: [String] // capability names
}, { collection: collectionName });

Upvotes: 0

Rik Leigh
Rik Leigh

Reputation: 1328

I found a few problems when trying to reproduce this locally.

You're not calling next() in newsSchema.pre('save')

Should be

newsSchema.pre('save', function(next){
    if( !this.addedOn ) this.addedOn = new Date();
    if( !this.addedBy ) this.addedBy = adminUser;
    next();
});

You also need to make sure that you are connected to the db before doing any of this stuff, not sure if you are or not since i didn't see that part of the code.

Upvotes: 5

supershabam
supershabam

Reputation: 706

It looks like the problem is in your news schema's save middleware.

newsSchema.pre('save', function(next){
    if( !this.addedOn ) this.addedOn = new Date();
    if( !this.addedBy ) this.addedBy = {first: "admin", last: "admin"};
});

Your function receives a "next" callback which you must execute to let mongoose know that you are done and ready to save the document. Since you're not calling it, it could explain why you get nothing saved, and also no errors.

Try just calling next like this:

newsSchema.pre('save', function(next){
    if( !this.addedOn ) this.addedOn = new Date();
    if( !this.addedBy ) this.addedBy = {first: "admin", last: "admin"};
    next();
});

Upvotes: 24

Related Questions