Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create interdependent schemas in Mongoose?

I have two Schemas and I want them to interact with eachother. For instance:

// calendar.js
var mongoose = require('mongoose');
var Scema = mongoose.Schema;
var Day = mongoose.model('Day');

var CalendarSchema = new Schema({
  name: { type: String, required: true },
  startYear: { type: Number, required: true }
});

CalendarSchema.methods.getDays = function(cb){
   Day.find({ cal: this._id }, cb);
}

module.exports = mongoose.model('Calendar', CalendarSchema);


// day.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
var Calendar = mongoose.model('Calendar');    

var DaySchema = new Schema({
  cal: { type: ObjectId, required: true },
  date: { type: Number, required: true },
  text: { type: String, default: 'hello' }
});

DaySchema.methods.getCal = function(cb){
   Calendar.findById(this.cal, cb);
}

module.exports = mongoose.model('Day', DaySchema);   

However, I get an error because each schema depends on the other one. Is there a way to get this working using Mongoose? I include them like this:

// app.js
require('./models/calendar');
require('./models/day');
like image 232
Robert Martin Avatar asked Aug 23 '12 21:08

Robert Martin


People also ask

Is Mongoose an ODM or ORM?

Mongoose is an ODM that provides a straightforward and schema-based solution to model your application data on top of MongoDB's native drivers.

Which schema types are not supported by Mongoose?

Mongoose does not natively support long and double datatypes for example, although MongoDB does. However, Mongoose can be extended using plugins to support these other types.


1 Answers

I realize this is an ancient thread, but I'm sure posting the solution will help others down the road.

The solution is to export the module before requiring the interdependent schemas:

// calendar.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var CalendarSchema = new Schema({
  name: { type: String, required: true },
  startYear: { type: Number, required: true }
});

module.exports = mongoose.model('Calendar', CalendarSchema);

// now you can include the other model and finish definining calendar
var Day = mongoose.require('./day');    
CalendarSchema.methods.getDays = function(cb){
   Day.find({ cal: this._id }, cb);
}


// day.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;   

var DaySchema = new Schema({
  cal: { type: ObjectId, required: true },
  date: { type: Number, required: true },
  text: { type: String, default: 'hello' }
});

module.exports = mongoose.model('Day', DaySchema);

// same thing here. require after exporting
var Calendar = require('./calendar'); 

DaySchema.methods.getCal = function(cb){
   Calendar.findById(this.cal, cb);
}

It really is that simple. Explanation by Brian Bickerton can be found here:

http://tauzero.roughdraft.io/3948969265a2a427cf83-requiring-interdependent-node-js-modules

It's nice to be able to use functions by name within a module instead of the lengthy module.exports.name. It's also nice to have a single place to look and see everything to be exported. Typically, the solution I've seen is to define functions and variables normally and then set module.exports to an object containing the desired properties at the end. This works in most cases. Where it breaks down is when two modules are inter-dependent and require each other. Setting the exports at the end leads to unexpected results. To get around this problem, simply assign module.exports at the top, before requiring the other module.

like image 72
mz3 Avatar answered Oct 16 '22 16:10

mz3