You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

预期效果示例

  1. vendors非空场景
    原Product文档:
const product = {
  mainVendor: 'mainVendorObjectId',
  vendors: ['secondVendorObjectid', 'thirdVendorObjectId']
}

删除_id为mainVendorObjectId的Vendor后,更新结果:

const product = {
  mainVendor: 'secondVendorObjectId',
  vendors: ['thirdVendorObjectId']
}
  1. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 02:46:00