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

如何在NestJS中更新MongoDB数据前删除同ID旧数据?

需求:通过ID更新MongoDB数据前先删除原有数据

现有代码

controller.ts

public updateVendorServiceSpecialPrice = async (req: Request, res: Response, next: NextFunction): Promise<Response | void> => {
    try {
        if (req.body.vendorServiceId!='') {
            let results = await this.ServicesService.updateVendorServicesSpecialPrice(req.params.vendorServiceId, req.body);
            if (results != false) {
                this.success(res, 'Updated Successfully', 200, results._id);
            }
        } 
        return await this.error(res, 'Something Went Wrong!.', 500);
    } catch (e) {
        next(e)
    }
}

service.ts

public async updateVendorServicesSpecialPrice(
    vendorServiceId: any,
    data: any
): Promise<any | Error> {
    try {
        return new Promise((resolve, reject) => {
            vendorServiceSpecialPriceSchema.findByIdAndUpdate(
                vendorServiceId,
                { ...data },
                (err: any, success: any) => {
                    if (err) {
                        reject(err);
                    }
                    if (!success) {
                        resolve(false);
                    } else {
                        resolve(success);
                    }
                }
            );
        });
    } catch (e) {
        console.log('service error\n', e);
        throw e;
    }
}

你的尝试实现

public async updateVendorServicesSpecialPrice(
    vendorServiceId: any,
    data: any
): Promise<any | Error> {
    try {
        return new Promise((resolve, reject) => {
            vendorServiceSpecialPriceSchema.deleteOne({vendorServiceId})
            vendorServiceSpecialPriceSchema.findOneAndUpdate(
                vendorServiceId,
                { ...data },
                { returnNewDocument: true },
                (err: any, success: any) => {
                    if (err) {
                        reject(err);
                    }
                    if (!success) {
                        resolve(false);
                    } else {
                        resolve(success);
                    }
                }
            );
        });
    } catch (e) {
        console.log('service error\n', e);
        throw e;
    }
}

问题分析

你的尝试存在几个关键问题:

  • 异步操作未等待:deleteOne是异步方法,你没有等待它执行完成就调用findOneAndUpdate,两个操作并行执行,可能出现旧数据未删除就执行更新,或删除后更新找不到文档的情况。
  • 删除条件错误:deleteOne({vendorServiceId})的查询条件是匹配vendorServiceId字段,但findByIdAndUpdate是根据MongoDB默认的_id主键查找的,这里应该用{ _id: vendorServiceId }作为删除条件。
  • 逻辑矛盾:删除文档后执行findOneAndUpdate,如果未设置upsert: true,该方法找不到对应文档时不会创建新文档,最终会返回false,无法实现“更新”的效果。

正确实现流程

要实现“删除旧数据后用同一ID更新为新数据”,正确步骤如下:

  1. 根据指定ID删除原有文档,确保使用_id作为查询条件。
  2. 等待删除操作完成后,用传入的新数据创建新文档,并手动指定_id为原来的ID,保证ID不变,达到“更新”效果。
  3. 处理过程中的异常,确保错误能被正确捕获和抛出。

同时建议使用Mongoose的async/await语法代替回调嵌套,让代码更简洁易读。

最终正确的service.ts代码

public async updateVendorServicesSpecialPrice(
    vendorServiceId: any,
    data: any
): Promise<any | Error> {
    try {
        // 第一步:删除原有数据,根据_id查找
        await vendorServiceSpecialPriceSchema.deleteOne({ _id: vendorServiceId });
        
        // 第二步:创建新数据,指定_id为原ID
        const newDoc = await vendorServiceSpecialPriceSchema.create({
            ...data,
            _id: vendorServiceId // 确保新文档使用原ID
        });
        
        return newDoc;
    } catch (e) {
        console.log('service error\n', e);
        throw e;
    }
}

额外说明

  • 如果业务允许“替换”而非先删后插,可使用findByIdAndReplace方法,但该方法不会删除旧文档,而是直接替换内容,不符合当前需求。
  • controller中的判断逻辑req.body.vendorServiceId!=''存在问题,req.params.vendorServiceId才是传入的目标ID,建议改为检查该参数是否存在。

内容的提问来源于stack exchange,提问作者user20219125

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 09:45:43