基于NodeJS Joi实现仅提交修改后数据至MongoDB的方法
解决方案
要实现仅提交用户修改过的字段到数据库,核心思路是先获取用户的原始数据,和请求 payload 对比后筛选出差异字段,再进行验证与更新。具体步骤如下:
1. 查询用户原始数据
在验证请求 payload 前,先从数据库获取该用户的当前数据,作为对比基准:
const originalUser = await getUserById(id); // 请确保你有对应的查询方法 if (!originalUser) { res.status(404).json({ message: `user ${id} not found` }); return; }
2. 筛选修改过的字段
遍历请求 payload 的所有键,和原始数据逐一对比,只保留值不同的字段:
const updatedFields: Partial<IUser> = {}; Object.keys(req.body).forEach(key => { // 处理类型兼容问题 if (req.body[key] !== originalUser[key as keyof IUser]) { updatedFields[key as keyof IUser] = req.body[key]; } }); // 若没有任何修改,直接返回提示 if (Object.keys(updatedFields).length === 0) { res.json({ message: `user ${id} no changes to update`, user: originalUser }); return; }
3. 验证并更新筛选后的字段
用你的 Joi Schema 验证筛选后的字段,确认合法后提交到数据库更新:
try { await userEditSchema.validateAsync(updatedFields); } catch (error) { res.status(400).json({ error }); return; } try { const user = await updateUserById(id, updatedFields); res.json({ message: `user ${id} updated`, user }); } catch (error) { res.status(500).json({ error }); }
整合后的完整代码
优化后的 updateUser 函数如下:
const updateUser = async (req: MyR, res: Response): Promise<void> => { const { id } = req.params; try { // 获取原始用户数据 const originalUser: IUser | null = await getUserById(id); if (!originalUser) { res.status(404).json({ message: `user ${id} not found` }); return; } // 筛选差异字段 const updatedFields: Partial<IUser> = {}; Object.keys(req.body).forEach(key => { if (req.body[key] !== originalUser[key as keyof IUser]) { updatedFields[key as keyof IUser] = req.body[key]; } }); if (Object.keys(updatedFields).length === 0) { res.json({ message: `user ${id} no changes to update`, user: originalUser }); return; } // 验证字段合法性 await userEditSchema.validateAsync(updatedFields); // 执行数据库更新 const user = await updateUserById(id, updatedFields); res.json({ message: `user ${id} updated`, user }); } catch (error) { if ((error as Error).name === 'ValidationError') { res.status(400).json({ error }); } else { res.status(500).json({ error }); } } };
额外说明
- 若用户数据包含嵌套对象,需要递归对比字段值,上述代码仅处理顶层字段;
- 对于数组类型字段,浅对比可能不准确,可使用
lodash.isEqual进行深比较; - 你的 Joi Schema 中所有字段均为可选,刚好适配筛选后可能只有部分字段的场景。
内容的提问来源于stack exchange,提问作者mrvanagas
相关产品推荐
相关产品推荐

