NestJS中Mongoose一对一关联仍可创建多门店的原因问询
问题描述
我在NestJS中使用@nestjs/mongoose和mongoose实现MongoDB的一对一关联,现有owners和stores两个集合,要求每个owner只能拥有一个store。
已定义Schema如下:
owner.schema.ts
@Schema() export class Owner { /* 其他字段 */ @Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'Store' }) store: Store; }
store.schema.ts
@Schema() export default class Store { /* 其他字段 */ @Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'Owner', required: true, }) owner: Owner; }
store.service.ts中的创建方法:
async createStore(createStoreDto: CreateStoreDto, user: ReqUser) { // 创建store实体 const entity = { ...createStoreDto, owner: user.id, } const store = await this.storeModel.create(entity); const saved = await store.save() // 将store._id保存到owner.store字段 await this.ownerModel.updateOne({ email: user.email }, { store: saved._id }) return saved; }
但目前仍能为同一个owner创建多个store,请问原因是什么?
原因分析
当前代码只实现了创建store后关联到owner的逻辑,但没有从数据库层面限制stores集合中同一个owner字段不能重复:
StoreSchema的owner字段仅设置了required: true,没有添加唯一约束,MongoDB不会阻止同一个owner_id被多次插入到stores集合中;- 虽然创建store后会更新
owner的store字段,但这只是覆盖旧值,无法阻止新store被创建。
解决方案
1. 给Store的owner字段添加唯一索引
修改store.schema.ts中的owner字段配置,添加unique: true,让MongoDB强制约束同一个owner只能对应一个store:
@Schema() export default class Store { /* 其他字段 */ @Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'Owner', required: true, unique: true // 添加唯一约束 }) owner: Owner; }
注意:如果集合中已有重复的owner数据,需要先清理掉再添加该约束,否则会报错。
2. 优化创建逻辑(可选,提升用户体验)
在创建store前先检查该owner是否已拥有store,提前返回错误,避免触发数据库的唯一约束报错:
async createStore(createStoreDto: CreateStoreDto, user: ReqUser) { // 先检查该用户是否已有store const existingStore = await this.storeModel.findOne({ owner: user.id }); if (existingStore) { throw new BadRequestException('该用户已拥有店铺,无法重复创建'); } const entity = { ...createStoreDto, owner: user.id, } const store = await this.storeModel.create(entity); const saved = await store.save() await this.ownerModel.updateOne({ email: user.email }, { store: saved._id }) return saved; }
3. 使用事务保证原子性(可选)
如果需要确保「创建store」和「更新owner」两个操作要么都成功要么都失败,可以使用MongoDB事务:
async createStore(createStoreDto: CreateStoreDto, user: ReqUser) { const session = await mongoose.startSession(); session.startTransaction(); try { const existingStore = await this.storeModel.findOne({ owner: user.id }).session(session); if (existingStore) { throw new BadRequestException('该用户已拥有店铺,无法重复创建'); } const entity = { ...createStoreDto, owner: user.id, } const store = await this.storeModel.create([entity], { session }); const saved = store[0]; await this.ownerModel.updateOne( { email: user.email }, { store: saved._id }, { session } ); await session.commitTransaction(); return saved; } catch (error) { await session.abortTransaction(); throw error; } finally { session.endSession(); } }
内容的提问来源于stack exchange,提问作者Charisman Apriandi
相关产品推荐
相关产品推荐

