升级MongoDB Client至v6.8.0后Typegoose鉴别器与索引异常
Typegoose鉴别器索引升级后出现partialFilterExpression问题的解决
问题描述
将MongoDB Client从v4.7.x升级到v6.8.0后,使用Typegoose定义的鉴别器模型,其继承自父类的唯一索引被自动添加了partialFilterExpression,导致(make, color)的唯一性约束仅对单个鉴别器(如mazda或cadi)生效,而非全局生效。
原模型定义:
@index({ make: 1, color: 1 }, { unique: true, background: false }) @modelOptions({ options: { allowMixed: Severity.ALLOW }, schemaOptions: { collection: 'cars', discriminatorKey: 'make' }, }) class Car extends defaultClasses.TimeStamps { @prop({ required: true }) make: string; @prop({ required: true }) color: string; } const CarModel = getModelForClass(Car); class Mazda extends Car {} const MazdaModel = getDiscriminatorModelForClass(CarModel, Mazda, 'mazda'); class Cadillac extends Car {} const CadillacModel = getDiscriminatorModelForClass(CarModel, Cadillac, 'cadi');
升级后调用listIndex()返回的索引带有partialFilterExpression,示例:
[{"v":2,"unique":true,"key":{"make":1,"color":1},"name":"make_1_color_1","background":false,"partialFilterExpression":{"make":"mazda"}}]
原因
MongoDB Node.js驱动v6.x或Typegoose的更新中,鉴别器模型继承父类索引时,会自动为索引添加partialFilterExpression,将索引范围限制到当前鉴别器的discriminatorKey值——默认行为是避免不同鉴别器之间的索引冲突,但不符合全局唯一约束的需求。
解决方法
方法1:手动创建全局唯一索引(推荐)
跳过鉴别器自动继承索引的逻辑,直接在父模型上手动创建全局索引:
@modelOptions({ options: { allowMixed: Severity.ALLOW }, schemaOptions: { collection: 'cars', discriminatorKey: 'make' }, }) class Car extends defaultClasses.TimeStamps { @prop({ required: true }) make: string; @prop({ required: true }) color: string; } const CarModel = getModelForClass(Car); // 手动添加全局唯一索引 await CarModel.createIndex({ make: 1, color: 1 }, { unique: true, background: false }); // 创建鉴别器 class Mazda extends Car {} const MazdaModel = getDiscriminatorModelForClass(CarModel, Mazda, 'mazda'); class Cadillac extends Car {} const CadillacModel = getDiscriminatorModelForClass(CarModel, Cadillac, 'cadi');
方法2:禁用鉴别器的索引继承
如果坚持使用装饰器定义父类索引,可在创建鉴别器时禁用索引继承:
@index({ make: 1, color: 1 }, { unique: true, background: false }) @modelOptions({ options: { allowMixed: Severity.ALLOW }, schemaOptions: { collection: 'cars', discriminatorKey: 'make' }, }) class Car extends defaultClasses.TimeStamps { @prop({ required: true }) make: string; @prop({ required: true }) color: string; } const CarModel = getModelForClass(Car); // 创建鉴别器时禁用索引继承 class Mazda extends Car {} const MazdaModel = getDiscriminatorModelForClass(CarModel, Mazda, 'mazda', { discriminatorOptions: { inheritIndexes: false } }); class Cadillac extends Car {} const CadillacModel = getDiscriminatorModelForClass(CarModel, Cadillac, 'cadi', { discriminatorOptions: { inheritIndexes: false } });
验证
执行await CarModel.listIndexes(),返回的索引应无partialFilterExpression:
[{"v":2,"unique":true,"key":{"make":1,"color":1},"name":"make_1_color_1","background":false}]
此时插入不同make但相同color的文档会触发唯一约束错误,符合全局唯一的需求。
内容的提问来源于stack exchange,提问作者Felix Koblenz
相关产品推荐
相关产品推荐

