首页 > 解决方案 > 为什么 mongodb upsert 计数器不反映实际变化?

问题描述

考虑以下查询

var collectionName = "test";
db.createCollection(collectionName);
db.getCollection(collectionName).insert({
  "_id" : 1, "char" : "Gandalf", "class" : "barbarian", "lvl" : 20
});

db.getCollection(collectionName).bulkWrite([
    { 
      insertOne: {
        "document": {
            "_id" : 2, "char" : "Dithras", "class" : "barbarian", "lvl" : 4
        }
      }
    },
    { 
      updateOne: { 
        filter: { "_id": 1}, 
        update: { $set: {"class" : "mage"} }, 
        upsert: true 
      } 
    }
])

结果是:

{
    "acknowledged" : true,
    "deletedCount" : 0.0,
    "insertedCount" : 1.0,
    "matchedCount" : 1.0,
    "upsertedCount" : 0.0,
    "insertedIds" : {
        "0" : 2.0
    },
    "upsertedIds" : {}
}

我的问题是为什么不更新id:1文档upsertedIds?这个文档不是刚刚用 upsert 更新了吗?还是我错过了什么?

根据文档,upsert如果它没有找到任何文档,它只会添加信息(所以它实际上更像inserted),但这种情况下我不知道哪些项目得到了更新。

执行查询时是否可以获取修改了哪些文档?


为避免 XY 问题:我希望查看失败的批量操作项(例如,当尝试使用 更新不存在的文档时upsert:false)以及触发失败的日志 ID。

标签: mongodb

解决方案


您可以在准备批量更新时收集文档 ID,然后检查更新后哪些不存在。例如,对于您更新的文档 ID 1、2 和 3upsert:false

db.test.aggregate([
    { $group: { _id: null }},    
    { $project: { _id: [ 1, 2, 3 ] }},
    { $unwind: "$_id" },
    { $lookup: {
       from: "test",
       localField: "_id",
       foreignField: "_id",
       as: "exists"
    }},
    { $match: { exists: { $size:0 }}},
    { $project: { exists:0 }}
])

将返回与任何文档都不匹配的过滤器的 id,即您的术语中的“失败”。


推荐阅读