I'm having a massive headache try to share some common schema definitions via a module to all the other modules in my code base.
I have a myproj_schemas module that contains these two schemas:
var mongoose = require('mongoose'),
util = require("util"),
Schema = mongoose.Schema;
var BaseProfileSchema = function() {
Schema.apply(this, arguments);
this.add({
_user: {type: Schema.Types.ObjectId, ref: 'User', required: true},
name: {type: String, required: true},
bio: {type: String, required: true},
pictureLink: String
});
};
util.inherits(BaseProfileSchema, Schema);
module.exports = BaseProfileSchema;
And
var mongoose = require('mongoose'),
BaseProfileSchema = require('./base_profile_schema.js'),
Schema = mongoose.Schema;
var entSchemaAdditions = {
mentors: {type: Schema.Types.ObjectId, ref: 'Mentor'}
};
var entrepreneurSchema = new BaseProfileSchema(entSchemaAdditions);
module.exports = entrepreneurSchema;
Mentors is also defined in another file.
My unit tests for these both work in the schemas module.
When I npm install this module and try to create using
Entrepreneur = db.model('Entrepreneur', entrepreneurSchema),
I get the following error:
TypeError: Undefined type at paths.mentors
Did you try nesting Schemas? You can only nest using refs or arrays.
If I use the same code in my local module, then no problem. If I reference the schema file directly in the require (e.g. require('../node_modules/myproj_schemas/models/ent_schema') then I get the error.
I'm fairly sure it wasn't breaking like this earlier, but I've backed out all the changes and it is still not working.
I'm drawing a complete blank, and any suggestions would be gratefully received.
EDIT:
I've created a new Schemas module. It has one Schema:
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({
email: String
});
module.exports = userSchema;
This also fails when packaged up in a module and npm install'd to other modules.
Running on OS X
js Package Manager (npm) is the default and most popular package manager in Node. js ecosystem that is primarily used to install and maintain external modules in Node. js application. Users can basically install the node modules needed for their application using npm.
It implies the file name of the current module. It refers to the directory name of the current module. Note that every file in Node. js will wrap every file that it executes.
If you are getting the "Cannot find module" error when trying to run a local file, make sure that the path you passed to the node command points to a file that exists. For example, if you run node src/index. js , make sure that the path src/index. js points to an existing file.
Personally I created separate "common" project with an init method to register all of the models with mongodb, and call the init method in the app.js file of any apps that need access to the models.
package.json - In the shared project, set your package.json
file to contain the following entry:
"main": "index.js"
Add a model - Create a new models
folder within your shared project, to contain all of your mongoose schemas and plugins. Add your userSchema file to the models folder and name it user.js
.
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({
email: String
});
module.exports = mongoose.model('User', userSchema);
index.js - Then in the project's root index.js
file create a shared object that can be used by your apps, exposing the models and an init
method. There's many ways to code this, but here's how I'm doing it:
function Common() {
//empty array to hold mongoose Schemas
this.models = {};
}
Common.prototype.init = function(mongoose) {
mongoose.connect('your mongodb connection string goes here');
require('./models/user');
//add more model references here
//This is just to make referencing the models easier within your apps, so you don't have to use strings. The model name you use here must match the name you used in the schema file
this.models = {
user: mongoose.model('User')
}
}
var common = new Common();
module.exports = common;
common
project - However you want to reference your shared project, add the reference to the shared project in the package.json
file within your app and give it a name of common
. Personally I used GitHub to store the project and referenced the repository path. Since my repository was private I had to use a key in the path, which is covered on the GitHub support site.Init the models in your app - In the start script for your app (let's assume it's app.js
for this example) add the reference to your common
project and call the init
method to connect to the mongodb server and register the models.
//at the top, near your other module dependencies
var mongoose = require('mongoose')
, common = require('common');
common.init(mongoose);
Use the model anywhere in your app - Now that mongoose has the connection pool established and the models have been registered, you can use the models is any of the classes within your app. For example, say you have a page that displays information about a user
you could do it like this (untested code, just wrote this for an example):
var common = require('common');
app.get('/user-profile/:id', function(req, res) {
common.models.user.findById(req.params.id, function(err, user) {
if (err)
console.log(err.message); //do something else to handle the error
else
res.render('user-profile', {model: {user: user}});
});
});
EDIT
Sorry, I didn't see the line where you were inheriting one schema from another. As one of the other answers stated, mongoose already offers the concept of a plugin
. In your example above, you would do this:
In your common module, under '/models/base-profile-plugin.js'
module.exports = exports = function baseProfilePlugin(schema, options){
//These paths will be added to any schema that uses this plugin
schema.add({
_user: {type: Schema.Types.ObjectId, ref: 'User', required: true},
name: {type: String, required: true},
bio: {type: String, required: true},
pictureLink: String
});
//you can also add static or instance methods or shared getter/setter handling logic here. See the plugin documentation on the mongoose website.
}
In your common module, under '/models/entrepreneur.js
var mongoose = require('mongoose')
, basePlugin = require('./base-profile-plugin.js');
var entrepreneurSchema = new mongoose.Schema({
mentors: {type: Schema.Types.ObjectId, ref: 'Mentor'}
});
entrepreneurSchema.plugin(basePlugin);
module.exports = mongoose.model('Entrepreneur', entrepreneurSchema);
Why don't you create a mongoose plugin for common schema like this https://github.com/Keeguon/mongoose-behaviors/blob/master/lib/timestampable.js
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With