如何在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更新为新数据”,正确步骤如下:
- 根据指定ID删除原有文档,确保使用
_id作为查询条件。 - 等待删除操作完成后,用传入的新数据创建新文档,并手动指定
_id为原来的ID,保证ID不变,达到“更新”效果。 - 处理过程中的异常,确保错误能被正确捕获和抛出。
同时建议使用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
相关产品推荐
相关产品推荐

