【问题标题】:Why would this upsert fail with a duplicate id exception?为什么这个 upsert 会因重复的 id 异常而失败?
【发布时间】:2026-01-28 03:25:01
【问题描述】:

这个不时出现。我将操作作为 upsert 完成,但每隔一段时间,服务就会崩溃,因为它遇到了这个错误,我什至不明白它是怎么可能的。我尝试使用 SurveyId 作为匹配键来执行 upsert:

await _surveyRepository.DatabaseCollection.UpdateOneAsync(
    Builders<SurveyData>.Filter.Eq(survey => survey.SurveyId, surveyData.SurveyId),
    Builders<SurveyData>.Update
        .Set(survey => survey.SurveyLink, surveyData.SurveyLink)
        .Set(survey => survey.ClientId, surveyData.ClientId)
        .Set(survey => survey.CustomerFirstName, surveyData.CustomerFirstName)
        .Set(survey => survey.CustomerLastName, surveyData.CustomerLastName)
        .Set(survey => survey.SurveyGenerationDateUtc, surveyData.SurveyGenerationDateUtc)
        .Set(survey => survey.PortalUserId, surveyData.PortalUserId)
        .Set(survey => survey.PortalUserFirst, surveyData.PortalUserFirst)
        .Set(survey => survey.PortalUserLast, surveyData.PortalUserLast)
        .Set(survey => survey.Tags, surveyData.Tags),
    new UpdateOptions { IsUpsert = true })
.ConfigureAwait(false);

我偶尔会收到这个错误:

消息:写入操作导致错误。 E11000 重复 键错误收集:surveys.surveys 索引:SurveyId 重复键:{: "" }

id 是 Guid 的字符串表示形式,在 mongo 中设置为唯一。

那么为什么会发生这种情况呢?我的理解是,如果找到密钥,它将更新定义的属性,如果没有,它将插入。这不正确吗?因为,这就是我需要的效果。

C#驱动版本为2.4.1.18

【问题讨论】:

    标签: mongodb mongodb-.net-driver


    【解决方案1】:

    发生这种情况是因为根据Jira ticket

    在使用 upsert:true 选项进行更新期间,两个(或更多)线程可能会尝试使用相同的查询谓词进行 upsert 操作,并且在未找到匹配项时,线程将尝试插入新文档。两个插入都将(并且应该)成功,除非第二个导致唯一约束违规。

    【讨论】:

      【解决方案2】:

      据我了解,如果它找到密钥,它将更新 定义的属性,如果没有,它将插入。这不正确吗

      是的,这就是 upsert 所做的。新插入的文档将包含更新查询的 criteria 部分(在您的情况下是surveyId)以及 update modify 部分(所有其他指定字段)中的所有字段。
      您需要在查询中设置 upsert=false。那么它只会更新符合条件的文档,如果没有找到匹配则更新失败。

      【讨论】:

      • 这不是预期的效果。那只是一个更新;我需要一个更新。如果找到 id,它应该使用指定的数据更新记录,如果找不到,则使用提供的字段插入一个新记录。它永远不会失败。