Mongoose删除Vendor时将Product的mainVendor设为vendors首项或null
Mongoose删除Vendor记录联动更新Product关联字段实现
问题背景
现有两个Mongoose数据模型定义如下:
// Product model const ProductSchema = { vendors: [{ type: Schema.Types.ObjectId, ref: 'Vendor' }], mainVendor: { type: Schema.Types.ObjectId, ref: 'Vendor' }, } // Vendor model const VendorSchema = { ... }
需要实现的逻辑:删除某条Vendor记录时,对所有mainVendor字段值为被删除Vendor_id的Product文档做如下处理:
- 若
vendors数组非空,将mainVendor替换为数组第一个元素,同时把该元素从vendors数组中移除 - 若
vendors数组为空,直接将mainVendor设为null
预期效果示例
- vendors非空场景
原Product文档:
const product = { mainVendor: 'mainVendorObjectId', vendors: ['secondVendorObjectid', 'thirdVendorObjectId'] }
删除_id为mainVendorObjectId的Vendor后,更新结果:
const product = { mainVendor: 'secondVendorObjectId', vendors: ['thirdVendorObjectId'] }
- vendors为空场景
原Product文档:
const product = { mainVendor: 'mainVendorObjectId', vendors: [] }
删除对应Vendor后,更新结果:
const product = { mainVendor: null, vendors: [] }
现有问题代码
当前在findOneAndDelete的post钩子中编写的代码无法生效,且vendors为空时不能正确将mainVendor设为null:
VendorSchema.post('findOneAndDelete', async function (res: TVendorModel) { try { const products = await ProductModel.updateMany( { mainVendor: res._id }, { $expr: { $set: { mainVendor: '$vendors.0' } } } ); } catch (error) { console.error(error); } });
正确实现代码
现有代码存在3个核心问题:
- 语法错误:
$expr是查询阶段操作符,不能直接放在更新对象中使用,更新时要读取文档自身字段做计算必须用聚合更新管道 - 逻辑缺失:没有实现「将选为新mainVendor的第一个元素从vendors数组移除」的逻辑
- 空值兼容问题:直接取
$vendors.0在数组为空时返回字段缺失值,不会自动转为null
将post钩子代码替换为以下版本即可:
VendorSchema.post('findOneAndDelete', async function (res: TVendorModel) { if (!res) return; try { await ProductModel.updateMany( { mainVendor: res._id }, [ { $set: { // 取vendors第一个元素,数组为空时返回null mainVendor: { $ifNull: [{ $first: '$vendors' }, null] }, // 截取vendors从索引1开始的剩余元素,相当于移除第一个元素 vendors: { $slice: ['$vendors', 1, { $size: '$vendors' }] } } } ] ); } catch (error) { console.error('联动更新Product关联字段失败:', error); } });
实现说明
- 更新参数传入数组时,Mongoose会自动识别为聚合更新管道,支持在更新逻辑中引用文档自身字段做运算
$first用于快速取数组第一个元素,配合$ifNull兼容数组为空的场景,强制返回null$slice实现数组截取,从索引1开始取到数组末尾,刚好完成「弹出第一个元素作为新mainVendor」的逻辑- 新增空值判断,未查询到待删除的Vendor时直接返回,避免执行无意义的更新操作
内容的提问来源于stack exchange,提问作者PYTHON DEVELOPER999
相关产品推荐
相关产品推荐

