MongoDB首次新增并更新对象内键的实现求助
MongoDB 文档数组新增/更新问题解决方案
问题分析
你的代码存在几个核心问题:
- 查询条件里的
users: { $elemMatch: { id: data.id2 } }会导致首次插入(文档和users数组均不存在)时匹配失败,upsert生成的文档不符合预期。 $inc: { 'users.point': ... }未指定数组内的具体目标元素,MongoDB无法定位到要更新的对象。- 同时使用
$addToSet和$inc逻辑冲突,无法同时处理「新增数组元素」和「更新已有元素」的场景。
正确实现代码
要实现「首次创建文档并添加users元素,已有文档时更新对应user的point,无对应user则新增」的需求,可通过聚合管道更新结合upsert完成:
// 假设data结构为:{ id: '2022-08-06', id2: '345456', point: 1 } client.db(dbProject).collection('test').updateOne( { '_id': data.id }, // 仅匹配文档_id,不提前过滤users数组 [ { $set: { users: { $cond: [ { $in: [data.id2, '$users.id'] }, // 判断users中是否存在目标id // 存在则更新对应user的point { $map: { input: '$users', as: 'user', in: { $mergeObjects: [ '$$user', { point: { $add: ['$$user.point', data.point] } } ] } } }, // 不存在则新增user元素 { $concatArrays: ['$users', [{ id: data.id2, point: data.point }]] } ] } } } ], { upsert: true, setDefaultsOnInsert: { users: [] } // 首次插入时初始化users为空数组 } );
代码说明
- 查询逻辑:仅通过
_id匹配文档,避免因users数组不存在导致首次插入失败。 - 聚合管道判断:用
$cond分支处理两种场景:- 存在目标user时,用
$map遍历数组并更新对应元素的point值。 - 不存在目标user时,用
$concatArrays追加新的user对象。
- 存在目标user时,用
- 初始化处理:
setDefaultsOnInsert确保首次插入时users数组为空,避免$concatArrays报错。
如果仅需首次创建指定结构的文档,可简化为:
client.db(dbProject).collection('test').updateOne( { '_id': '2022-08-06' }, { $set: { users: [{ id: '345456', point: 1 }] } }, { upsert: true } );
内容的提问来源于stack exchange,提问作者Mezei
相关产品推荐
相关产品推荐

