feathers-mongoose is a database adapter for Mongoose, an object modeling tool for MongoDB. Mongoose provides a straight-forward, schema-based solution to model your application data. It includes built-in type casting, validation, query building, business logic hooks and more.
$ npm install --save mongoose feathers-mongoose
We can create Mongoose services like this:
const mongoose = require('mongoose');
const service = require('feathers-mongoose');
// A module that exports your Mongoose model
const Message = require('./models/message');
// Make Mongoose use the ES6 promise
mongoose.Promise = global.Promise;
// Connect to a local database called `feathers`
mongoose.connect('mongodb://localhost:27017/feathers');
app.use('/messages', service({ Model: Message }));
Important: To avoid odd error handling behaviour, always set
mongoose.Promise = global.Promise
. If not available already, Feathers comes with a polyfill for native Promises.
See the Mongoose Guide for more information on defining your model.
The following options can be passed when creating a new Mongoose service:
Model
(required) - The Mongoose model definitionid
(default:_id
) [optional] - The name of the id propertypaginate
- A pagination object containing adefault
andmax
page size (see the Pagination chapter)lean
(default:false
) [optional] - When set to true runs queries faster by returning plain mongodb objects instead of mongoose models.overwrite
(default:true
) [optional] - Updates completely replace existing documents.
Here's a complete example of a Feathers server with a messages
Mongoose service.
$ npm install feathers feathers-rest body-parser mongoose feathers-mongoose
In message-model.js
:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const MessageSchema = new Schema({
text: {
type: String,
required: true
},
read: {
type: Boolean,
default: false
}
});
const Model = mongoose.model('Message', MessageSchema);
module.exports = Model;
Then in app.js
:
const feathers = require('feathers');
const rest = require('feathers-rest');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const service = require('feathers-mongoose');
const Model = require('./message-model');
// Tell mongoose to use native promises
// See http://mongoosejs.com/docs/promises.html
mongoose.Promise = global.Promise;
// Connect to your MongoDB instance(s)
mongoose.connect('mongodb://localhost:27017/feathers');
// Create a feathers instance.
const app = feathers()
// Enable REST services
.configure(rest())
// Turn on JSON parser for REST services
.use(bodyParser.json())
// Turn on URL-encoded parser for REST services
.use(bodyParser.urlencoded({extended: true}))
// Connect to the db, create and register a Feathers service.
app.use('/messages', service({
Model,
paginate: {
default: 2,
max: 4
}
}));
// Create a dummy Message
app.service('messages').create({
text: 'Server message'
}).then(function(message) {
console.log('Created message', message);
});
// Start the server.
const port = 3030;
app.listen(port, function() {
console.log(`Feathers server listening on port ${port}`);
});
You can run this example by using npm start
and going to localhost:3030/messages. You should see a paginated object with the message that we created on the server.
Version 3 of this adapter no longer brings its own Mongoose dependency, only accepts mongoose models and doesn't set up a database connection for you anymore. This means that you now need to make your own mongoose database connection and you need to pass in mongoose models changing something like
var MySchema = require('./models/mymodel')
var mongooseService = require('feathers-mongoose');
app.use('messages', mongooseService('message', MySchema, options));
To
var mongoose = require('mongoose');
var MongooseModel = require('./models/mymodel')
var mongooseService = require('feathers-mongoose');
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost:27017/feathers');
app.use('/messages', mongooseService({
Model: MongooseModel
}));
Mongoose by default gives you the ability to add validations at the model level. Using an error handler like the one comes with Feathers your validation errors will be formatted nicely right out of the box!
For more complex validations you really have two options. You can combine Mongoose's validation mechanism with a validation library like validator.js or you can do your validations at the service level using hooks.
With Validator.js
Here's an example of doing more complex validations at the model level with the validator.js validation library.
const validator = require('validator');
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
email: {
type: String,
validate: {
validator: validator.isEmail,
message: '{VALUE} is not a valid email!'
}
},
phone: {
type: String,
validate: {
validator: function(v) {
return /d{3}-d{3}-d{4}/.test(v);
},
message: '{VALUE} is not a valid phone number!'
}
}
});
const User = mongoose.model('user', userSchema);
Unless you passed lean: true
when initializing your service, the records returned from a query are Mongoose documents, so they can't be modified directly (You won't be able to delete properties from them).
To get around this, you can use the included toObject
hook to convert the Mongoose documents into plain objects. Let's modify the after hook's setup in the feathers-hooks example, above, to this:
app.service('messages').after({
all: [service.hooks.toObject({})]
});
The toObject
hook must be called as a function and accepts a configuration object with any of the options supported by Mongoose's toObject method. Additionally, a second parameter can be specified that determines which attribute of hook.result
will have its Mongoose documents converted to plain objects (defaults to data
).