MongoDB不同文档数组重复ID生成问题及解决方案咨询
解决MongoDB批量更新数组元素时重复生成ObjectId的问题
问题场景
使用updateMany给city集合所有文档的tags数组添加元素时,发现所有新插入的tag子文档ID完全重复(例如63ec8f47efbd82c8face341a)。
执行代码
await this.cityRepository.updateMany( {}, { $push: { tags: { title: tagValue.title, description: tagValue.description, applyToAllCity: tagValue.cityId ? false : true, }, }, }, );
City Schema定义
export class BaseCity extends Document { @Prop({ type: "String", required: true, }) _id: string; @Prop({ type: "String", unique: true }) code: string; @Prop({ type: "String", ref: Province.name }) province: string | Province; @Prop({ type: "String" }) faName: string; } @Schema({ timestamps: true }) @Schema({ collection: "city", virtuals: true, _id: false, timestamps: true }) export class City extends BaseCity { @Prop({ type: "String" }) imageName: string; @Prop({ index: true, type: "String" }) enName: string; @Prop({ type: "Number" }) displayOrder: number; @Prop({ type: "Boolean" }) isFeatured: boolean; @Prop({ type: "Boolean" }) isEnabled: boolean; @Prop({ type: Coordinate }) coordinate: Coordinate; @Prop([{ type: Region, ref: Region.name, default: [] }]) region: Region[]; @Prop([{ type: SubMenu }]) subMenu: SubMenu[]; @Prop([{ type: CityTags }]) tags: CityTags[]; } const CitySchema = SchemaFactory.createForClass(City); CitySchema.index({ faName: "text" }); export { CitySchema };
问题原因
Mongoose在执行updateMany这类批量更新操作时,只会生成一次子文档的ObjectId,并将这个ID复用给所有被更新文档的数组元素。因为updateMany是单次数据库请求,Mongoose不会为每个目标文档单独生成新的唯一ID。
解决方案
方案1:手动生成唯一ID
在构造tags元素时,手动为_id字段赋值新的ObjectId,确保每个子文档ID唯一:
import { ObjectId } from 'mongoose'; await this.cityRepository.updateMany( {}, { $push: { tags: { _id: new ObjectId(), // 手动生成唯一ID title: tagValue.title, description: tagValue.description, applyToAllCity: tagValue.cityId ? false : true, }, }, }, );
方案2:逐个文档单独更新
如果希望依赖Mongoose自动生成ID,可以先查询所有city文档,再逐个调用updateOne更新。这种方式会为每个子文档生成独立ID,但文档数量较多时会增加数据库请求次数,影响性能:
const cities = await this.cityRepository.find({}); for (const city of cities) { await this.cityRepository.updateOne( { _id: city._id }, { $push: { tags: { title: tagValue.title, description: tagValue.description, applyToAllCity: tagValue.cityId ? false : true, }, }, }, ); }
方案3:禁用子文档自动生成ID
如果业务上不需要CityTags子文档的_id字段,可以在CityTags的Schema定义中设置_id: false,彻底避免ID生成和重复问题:
@Schema({ _id: false }) // 添加此配置 export class CityTags { // 你的字段定义,例如: @Prop({ type: String }) title: string; @Prop({ type: String }) description: string; @Prop({ type: Boolean }) applyToAllCity: boolean; }
内容的提问来源于stack exchange,提问作者Amir Mohammad Beheshti
相关产品推荐
相关产品推荐

