问题
I'm currently using Mongoose ODM to manage database connections to MongoDB in a NodeJS application, and intercepting the connection using Mockgoose in Mocha tests. I've ran into an issue where my unique indexes are being ignored when performing an update to a document. I'm simply wrapping Mongoose with another package called Mongoose-bird, which just enables the use of promises.
One schema in particular is as follows:
// Gallery.js
'use strict';
var mongoose = require('mongoose-bird')(require("mongoose"));
var Schema = mongoose.Schema;
var ObjectId = Schema.Types.ObjectId;
var deepPopulate = require('mongoose-deep-populate')(mongoose);
var GallerySchema = new Schema({
_id: ObjectId,
type: String,
title: String,
slug: String,
_albums: [{
type: ObjectId,
ref: 'Albums'
}]
});
GallerySchema.index({ slug: 1 }, { unique: true });
GallerySchema.plugin(deepPopulate, {});
mongoose.model('Galleries', GallerySchema);
When calling Gallery.update(conditions, data, opts)
from my controller in a test, purposely setting the slug
to be a duplicate of another, it updates the document and then I end up with two documents with the same slug
path.
FYI, I've found a way around this by using the save()
function instead, which seems to obey the unique index without any questions.
However, as I'd prefer to use update()
over save()
(i.e. to update documents partially as opposed to the whole document each time), I'm interested to know if anyone else has had this same issue and how you have overcome it?
The application follows a standard MVC pattern based on MEAN.js so there's a bit more to it than just one model, though if I've left out anything which may be useful, please let me know.
Update
After looking into the source code of the Mockgoose NPM module, I can confirm the validation against the schema is never performed when running update(). There is an issue logged here: http://www.github.com/mccormicka/Mockgoose/issues/58
回答1:
Probably you are using mockgoose.reset
in a test hook (e.g. afterEach
). It drops the database and the indexes aren't created again during the execution.
The solution is removing models separately.
回答2:
Adding on to Diego's post. Calling mockgoose.helper.reset()
in a test hook to probably clear the collections in the temporary store also removes the indexes.
You should reset the indexes after calling reset using the snippet below.
await mockgoose.helper.reset()
const db = mongoose.connection
db.modelNames().map(async (model) => {
await db.models[model].createIndexes()
})
This fixed the problem for me. Hope this helps.
回答3:
From the mongoose docs
When your application starts up, Mongoose automatically calls ensureIndex for each defined index in your schema. Mongoose will call ensureIndex for each index sequentially, and emit an 'index' event on the model when all the ensureIndex calls succeeded or when there was an error.
While nice for development, it is recommended this behavior be disabled in production since index creation can cause a significant performance impact. Disable the behavior by setting the autoIndex option of your schema to false, or globally on the connection by setting the option config.autoIndex to false.
Since, mongoose sets the index on start, you got to debug the specific error, why mongoDb is not allowing to index, using the following code
//keeping autoIndex to true to ensure mongoose creates indexes on app start
GallerySchema.set('autoIndex', true);
//enable index debugging
GallerySchema.set('emitIndexErrors', false);
GallerySchema.on('error', function(error) {
// gets an error whenever index build fails
});
GallerySchema.index({ slug: 1 }, { unique: true });
Also, make sure autoIndex
is not set to false as mentioned in the mongoose doc, or better set it true explicitly as done above.
Additonally,
mongoose.set('debug', true);
The debug logging will show you the ensureIndex
call it's making for you to create the index.
来源:https://stackoverflow.com/questions/33594499/unique-index-ignored-when-updating-with-mongoose-mockgoose-in-nodejs