diegoaguilar
diegoaguilar

Reputation: 8376

How to properly use Mongoose models with Node.js?

I'm trying to use mongoose to control my db logic and transactions. I already got Schema definitions and I'm exporting the models.

Howver when i try to use a model, it will fail witl a message like:

return mongoose.model('Report', reportSchema); } has no method 'find'...

This is my Model export:

module.exports = (function() {

var mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;

    var reportSchema = mongoose.Schema({

        category: ObjectId,
        authorName: String,
        authorEmail: String,
        text: String,
        address: String,
        coordinates: {
          type: "Point",
          coordinates: [Number,Number]
        },
        date: {
            type: Date,
            default: new Date()
        },

        comments: Array
    });

    return mongoose.model('Report', reportSchema);
});

And this is how my controller functions are coded using mongoose inside:

module.exports = (function() {

    var mongoose = require('mongoose');
    var Report = require('../models/Report');
    var Category = require('../models/Category');

    function _getReports (request,response,next) {

        var take = request.query.take;
        var skip = request.query.skip;

        Report.find({}).limit(take).skip(skip).exec(function (err,reports) {

            callback(err,reports,response);
        });
    }

    function _getReport (request,response,next) {

        var id = request.params.id;

        Report.findById({_id: id}, function (err,report) {

            callback(err,report);
        });
    }

    function _createReport (request,response) {

        var newReport = new Report();

        newReport.text = request.body.text;
        newReport.category = request.body.category;
        newReport.author = request.session.userId;

        newReport.save(function (err,savedReport) {
            callback(err,savedReport._id,response);
        });

    }

    function _updateReport (request,response) {

        var id = request.params.id;
        var update = request.body.report;

        Report.findByIdAndUpdate(id, update, function (err,foundReport) {

            callback(err,foundReport,response);
        });
    }

    function _deleteReport (request,response) {

        var id = request.params.id;

        Report.findByIdAndRemove(id, function (err,foundReport) {
            callback(err,foundReport,response);
        });
    }

    function _getReports (request,response,next) {

        var take = request.query.take;
        var skip = request.query.skip;

        Report.find({}).limit(take).skip(skip).exec(function (err,reports){

            callback(err,reports,response);
        });
    }

    function _getCategories (request,response) {

        var take = request.query.take;
        var skip = request.query.skip;

        Report.find({}).limit(take).skip(skip).exec(function (err,reports) {

            callback(err,reports,response);
        });
    }

    function _getCategoryReports (argument) {

        var _id = mongoose.Types.ObjectId(request.params.id);

        Report.find({category:id},{category:false},function (err, foundReports) {
            callback(err,foundReports,response);
        });
    }

    function _createCategory (request,response) {

        var newCategory = new Category();

        newCategory.name = request.body.name;

        newCategory.save(function (err,savedCategory) {
            callback(err,savedCategory._id,response);
        });
    }

    function _updateCategory (request,response) {

        var id = request.params.id;
        var update = request.body.category;

        Category.findByIdAndUpdate(id, update, function (err,foundCategory) {

            callback(err,foundCategory,response);
        });
    }

    function _deleteCategory (request,response) {

        var id = request.params.id;

        Category.findByIdAndRemove(id, function (err,foundCategory) {
            callback(err,foundCategory,response);
        });
    }



    function callback (err,object,response) {

            if (err)
                response.status(500).send(JSON.stringify(err));

            response.send(JSON.stringify(object));
    }


    var apiController = {
        getReports: _getReports,
        getReport: _getReport,
        createReport: _createReport,
        updateReport: _updateReport,
        deleteReport: _deleteReport,
        getCategories: _getCategories,
        getCategoryReports: _getCategoryReports,
        createCategory: _createCategory,
        updateCategory: _updateCategory
    }

    return apiController;
})();

Before this, a mongoose connection is ensured:

var connectToMongoose = function (mongoose,app) {

    var connect = function () {
        var options = { server: { socketOptions: { keepAlive: 1 } } };
        mongoose.connect( 'mongodb://localhost/data4', options);
    }


    mongoose.connection.on('connected', function () {

        console.log('Connected to db');

        app.listen(32884, function() {
          console.log("Listening at \"data4 port\" @:32884");
        });
    })

    mongoose.connection.on('error', function (err) {
      console.log(err);
    });

    mongoose.connection.on('disconnected', function () {
        console.log('Disconnected from db, attempting to connect again...');
        app.close();
        connect();
    });

    connect();
};

module.exports = connectToMongoose;

Which is invoked by require('./db/mongoose-connect.js')(mongoose,app);

What am I doing wrong?

Upvotes: 1

Views: 500

Answers (2)

Wilson
Wilson

Reputation: 9136

When you export a function;

// file: A.js
module.exports = function () {
  //some logic
};

And you want to use it on another file, when you require the A file, you are importing a function and in order to use that function, you need to to invoke it.

// file: B.js
var A = require('./A.js');
A();

so your model is exporting a function

module.exports = (function() {

  var mongoose = require('mongoose'),
  Schema = mongoose.Schema,
  ObjectId = Schema.ObjectId;

  // ..
  // some code
  // ..

  return mongoose.model('Report', reportSchema);
});

and when you are importing your model from your controller, you need to execute your imported function so that your Report variable contains the model created:

    module.exports = (function() {

        var mongoose = require('mongoose');
        var Report = require('../models/Report') ();

I have created a gist of how you could write your code using modules without using IIFE. https://gist.github.com/wilsonbalderrama/d5484f3f530899f101dc actually if you download all those files on a folder and run:

$ sudo npm install
$ mocha

You could see that all the tests created for the controller are passing.


In addition you don't need to use IIFE in Node.JS since when you are creating a module because you already have an isolated scope in Node.JS using modules.

// IIFE
module.exports = (function() {

 var apiController = {
   getReport: function () {}
 }

  return apiController;
})();

In Node.JS you can export a object,

// GOOD WAY
module.exports = {
  getReport: function () {}
};

Upvotes: 0

richardgirges
richardgirges

Reputation: 1532

There are a couple issues here that I caught off the bat.

First off, I don't see a mongoose.connect() line that explicitly connects your mongoose ODM to a mongo server+database. An example would be:

var mongoose = require( 'mongoose' ),
Schema =        mongo.Schema,
ObjectId =      mongo.Schema.ObjectId;

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

Your schema export looks fine. But you're using an anonymous function as your export. Since you're doing that, your require statement needs to change a little:

var Report = require('../models/Report')();
var Category = require('../models/Category')();

Notice the () at the end of the require statements. You need to execute the function that you're defining as your model file's module.export.

EDIT: I see that you added your mongoose connect code. At this point, executing the module.exports function that you assign in the model file should allow your mongoose models to function as intended.

Upvotes: 1

Related Questions