Mongoose过滤无匹配时批量创建多个文档的实现问题
问题分析与解决方案
你的代码存在3个核心错误
- 过滤条件逻辑错误:你想要匹配未创建的标签执行插入,但你把过滤条件设为了
{"tagName": result},result是已存在的标签数组,当result为空时Mongoose会自动将数组参数转换为{ "$in": [] }的查询条件,该条件无法匹配任何文档,upsert时就会把查询条件的结构直接写入新文档,才会出现tagName: { "$in": [] }的异常结果。 - update参数格式错误:
$setOnInsert后需要传入单条文档的键值对,你直接传入了newTags数组,不符合MongoDB更新语法要求。 - 对
updateMany的upsert逻辑理解错误:updateMany开启upsert后,仅当没有匹配到任何文档时,才会最多插入1条新文档,无法实现批量插入多个缺失文档的需求,这是MongoDB的原生限制。
正确实现方案
你要实现「批量校验,不存在则创建」的需求,应该使用bulkWrite接口,给每个待创建的标签单独构造带upsert的更新操作,示例代码如下:
// 首先查询已创建的标签 const existTags: Tag[] = await tagModel.find({"tagName": tags}).select('tagName -_id').exec(); // 提取已存在的标签名 const existTagNames = existTags.map(item => item.tagName); // 筛选需要新增的标签 const toAddTags = tags.filter(tag => !existTagNames.includes(tag)); // 构造批量操作 const bulkOps = toAddTags.map(tagName => ({ updateOne: { filter: { tagName }, update: { $setOnInsert: { tagName, // 你需要设置的其他字段 } }, upsert: true } })); // 执行批量操作 await tagModel.bulkWrite(bulkOps);
关于$setOnInsert和过滤条件字段重复的说明
如果$setOnInsert中出现和过滤条件相同的字段,$setOnInsert的取值优先级更高,会直接覆盖过滤条件中的字段值写入新文档,你无需额外处理冲突。
内容的提问来源于stack exchange,提问作者Yechiam Weiss
相关产品推荐
相关产品推荐

