问题
If I leave mocha watching for changes, every time I save a file mongoose throws the following error:
OverwriteModelError: Cannot overwrite
Client
model once compiled
I know that mongoose won't allow to define a model twice, but I don't know how to make it work with mocha --watch
.
// client.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var clientSchema = new Schema({
secret: { type: String, required: true, unique: true },
name: String,
description: String,
grant_types: [String],
created_at: { type: Date, default: Date.now }
});
module.exports = mongoose.model('Client', clientSchema);
And here is the test
// client-test.js
var chai = require('chai');
var chaiHttp = require('chai-http');
var mongoose = require('mongoose');
var server = require('../../app');
var Client = require('../../auth/models').Client;
var should = chai.should();
chai.use(chaiHttp);
describe('client endpoints', function() {
after(function(done) {
mongoose.connection.close();
done();
});
it('should get a single client on /auth/client/{clientId} GET', function(done) {
var clt = new Client({
name: 'my app name',
description: 'super usefull and nice app',
grant_types: ['password', 'refresh_token']
});
clt.save(function(err) {
chai.request(server)
.get('/auth/client/' + clt._id.toString())
.end(function(err, res) {
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('client_id');
res.body.should.not.have.property('secret');
res.body.should.have.property('name');
res.body.should.have.property('description');
done();
});
});
});
});
回答1:
I had the same issue. My solution was to check whether the model was created/compiled yet, and if not then do so, otherwise just retrieve the model.
using mongoose.modelNames() you can get an array of the names of your models. Then use .indexOf to check if the model you want to get is in the array or not. If it is not, then compile the model, for example: mongoose.model("User", UserSchema)
, but if it is already defined (as is the case with mocha --watch), simply retrieve the model (don't compile it again), which you can do with for example: mongoose.connection.model("User")
.
This is a function which returns a function to do this checking logic, which itself returns the model (either by compiling it or just retrieving it).
const mongoose = require("mongoose");
//returns a function which returns either a compiled model, or a precompiled model
//s is a String for the model name e.g. "User", and model is the mongoose Schema
function getModel(s, model) {
return function() {
return mongoose.modelNames().indexOf(s) === -1
? mongoose.model(s, model)
: mongoose.connection.model(s);
};
}
module.exports = getModel;
This means you have to require your model a bit differently, since you are likely replacing something like this:
module.exports = mongoose.model("User", UserSchema);
which returns the model itself, with this:
module.exports = getModel("User", UserSchema);
which returns a function to return the model, either by compiling it or just retrieving it. This means when you require the 'User' model, you would want to call the function returned by getModel:
const UserModel = require("./models/UserModel")();
I hope this helps.
回答2:
Here is a simpler code for the function getModel() that George is proposing
function getModel(modelName, modelSchema) {
return mongoose.models[modelName] // Check if the model exists
? mongoose.model(modelName) // If true, only retrieve it
: mongoose.model(modelName, modelSchema) // If false, define it
}
For a larger explanation on how to define and require the model, look here
Hope this helps :)
来源:https://stackoverflow.com/questions/39035634/mocha-watch-and-mongoose-models