I'm developing a Mongoose plugin that archives documents on every update by cloning the original schema. However, I'm facing an issue with unique fields: when a field is marked as unique, Mongoose automatically creates an index for it in the cloned schema, even when I try to remove or disable it.
I need to create a clean version of the schema, where:
I tried manually setting unique: false for the fields, but the index still gets created or the setting is ignored. Interestingly, when I set required: false, that change is correctly applied.
Using a recursive function to set unique: false: I created the following function to traverse the schema and disable unique constraints:
const historySchema = schema.clone();
function setUniqueFalse(usedSchema: Schema) {
usedSchema?.eachPath((path, schemaType: any) => {
if (schemaType?.instance === 'Array' && schemaType?.casterConstructor?.schema) {
setUniqueFalse(schemaType.casterConstructor.schema);
} else {
if (schemaType?.options?.unique || schemaType?.OptionsConstructor?.unique) {
schemaType.unique(false);
schemaType.options.unique = false;
schemaType.OptionsConstructor.unique = false;
}
if (schemaType?.schema) {
setUniqueFalse(schemaType.schema);
}
}
});
}
setUniqueFalse(historySchema);
Using clearIndexes():
historySchema.clearIndexes();
Checking if clonedSchema.indexes() still contains unique constraints after modifications:
console.log(historySchema.indexes());
Manually dropping indexes after schema initialization:
MyArchivedModel.collection.dropIndexes();
This works, but I have to clear indexes every time an update or delete occurs.
How can I properly clone a Mongoose schema while ensuring that all unique constraints and indexes are removed?
You have a couple of options that might suit your needs.
Firstly, within your database connection just turn off auto indexing. For example:
mongoose.connect('mongodb://username:password@127.0.0.1:27017/archivedb', {
autoIndex: false
}).then(()=>{
console.log('Connected to archive database');
}).catch((err)=>{
console.log('Error in connection:', err);
});
This will of course disable all index creation for that connection so even ones you do want will not have an index created.
Secondly, within the schema definition you can disable auto indexing by passing in the options object on each schema:
const vendorSchema = new mongoose.Schema({
name: String,
contract: {
type: String,
enum: ['subscription', 'fixed', 'retainer']
}
},{ autoIndex: false });
However, since it sounds like you will be doing that on many schemas, and if this is your preferred approach, you can also use the set
method instead like so:
const vendorSchema = new mongoose.Schema({
name: String,
contract: {
type: String,
enum: ['subscription', 'fixed', 'retainer']
}
});
vendorSchema.set('autoIndex', false);