MongoDB单文档多层嵌套数组按条件批量插入多个对象实现问询
// 待插入的分数数组 const scoreList = [ { "sectionId": "section1", "itemName": "item1.1", "score": 10, "userId": 10 }, { "sectionId": "section1", "itemName": "item1.2", "score": 15, "userId": 10 }, { "sectionId": "section2", "itemName": "item2.1", "score": 33, "userId": 10 } ] // 动态拼接$push操作和arrayFilters const pushOps = {} const arrayFilters = [] scoreList.forEach((scoreItem, index) => { const secKey = `sec${index}` const itemKey = `item${index}` // 拼接push路径 pushOps[`sections.$[${secKey}].items.$[${itemKey}].scores`] = { userId: scoreItem.userId, score: scoreItem.score } // 拼接对应过滤器 arrayFilters.push({ [`${secKey}.id`]: scoreItem.sectionId }) arrayFilters.push({ [`${itemKey}.name`]: scoreItem.itemName, [`${itemKey}.scores.userId`]: { $ne: scoreItem.userId } }) }) // 执行单原子更新 db.collection.update( { id: 1 }, { $push: pushOps }, { arrayFilters: arrayFilters } )
逻辑说明
- 要求MongoDB版本≥3.6,利用arrayFilters支持自定义命名占位符的特性,为每个待插入的分数项生成独立的匹配规则,不同项的规则之间互不干扰
- 过滤器中同时校验section的id、item的name,以及当前item的scores数组中不存在对应userId的条目,和你之前单条插入的防重复逻辑完全一致
- 整个update是原子操作,所有插入要么全部执行成功,要么全部回滚,不会出现部分更新的情况
- 代码用动态拼接的方式生成操作参数,即使待插入的分数项数量很多,也不需要手动编写重复代码,固定场景下也可以手动写死所有操作和过滤器参数,效果完全一致
内容的提问来源于stack exchange,提问作者Arikael
相关产品推荐
相关产品推荐

