【问题标题】:Upserting in Mongo DB using official C# driver使用官方 C# 驱动程序在 Mongo DB 中进行更新插入
【发布时间】:2011-08-30 07:36:34
【问题描述】:

在 mongodb 的官方文档中,他们提到了 upserts,所以写一个 upsert 命令而不是:

if (_campaignRepo.Exists(camp))
{
    _campaignRepo.DeleteByIdAndSystemId(camp);
}

_campaignRepo.Save(camp);

如果可能的话,可以在数据库级别实现该逻辑的东西。那么如果有一个 upsert 的方法是什么?

【问题讨论】:

    标签: c# mongodb mongodb-.net-driver


    【解决方案1】:

    版本 2 的 MongoDB C# 驱动程序需要在写入命令中设置 IsUpsert 标志。此示例将 upsert 整个文档。

    var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } };
    var result = await collection.ReplaceOneAsync(
                    filter: new BsonDocument("_id", 123),
                    options: new ReplaceOptions { IsUpsert = true },
                    replacement: newDoc);
    

    版本 1 的 MongoDB C# 驱动程序在 Save 命令中实现此逻辑。

    var newDoc = new BsonDocument { { "_id", 123 }, { "someKey", "someValue" } };
    collection.Save(newDoc);
    

    Save 方法是 Insert 和 Update 的组合。 如果文档的 Id 成员有值,则假定它是现有文档,并且 Save 调用文档上的 Update(设置Upsert 标志以防万一它毕竟是一个新文档)。否则,假定它是一个新文档,并且 Save 在首先将新生成的唯一值分配给 Id 成员后调用 Insert。

    参考:http://mongodb.github.io/mongo-csharp-driver/1.11/driver/#save-tdocument-method

    注意:但这确实需要正确映射 Id 字段。更多信息在这里:http://mongodb.github.io/mongo-csharp-driver/1.11/serialization/#identifying-the-id-field-or-property

    【讨论】:

    • 新 API 无法再做到这一点。
    • 已更新。虽然我认为新的 API 使 upsert 命令更难使用。
    • 如果 newDocs ID 为空,即它是一个插入,则传递给过滤器的内容是什么?只是一个空的 bson 文档?
    • @BenCr 如果您只是进行普通插入而不是 upsert,那么您应该使用 InsertOneAsync 方法。这不需要指定 ID 字段,因为 MongoDB 将在插入期间创建一个,但您也可以创建这些 ID,而无需像 GUID 一样进入数据库,因此这取决于您。 C# 驱动程序文档中的更多信息:mongodb.github.io/mongo-csharp-driver/2.1/reference/driver/crud/…
    【解决方案2】:

    从驱动程序的 v2.0 开始,有一个新的仅异步 API。不应再使用旧 API,因为它是新 API 的阻塞外观,已被弃用。

    目前推荐的 upsert 文档方法是调用并等待 ReplaceOneAsync 并打开 IsUpsert 标志并使用与相关文档匹配的过滤器:

    Hamster hamster = ...
    var replaceOneResult = await collection.ReplaceOneAsync(
        doc => doc.Id == hamster.Id, 
        hamster, 
        new UpdateOptions {IsUpsert = true});
    

    您可以通过查看ReplaceOneResult.MatchedCount 来检查操作是插入还是更新:

    【讨论】:

    • 我正在尝试使用 ReplaceOneAsync 但它引发异常:“元素名称''无效”,我正在使用 updateOneasync 的过滤器,它可以工作但不能与 replaceone 一起使用。你能帮帮我吗?
    • UpdateOptions 已过时,使用新的 ReplaceOptions {IsUpsert = true});现在
    【解决方案3】:

    以下代码来自工作应用:

    weekplanStore.Update(
        Query.EQ("weekNumber", week),
        Update.Replace(rawWeekPlan),
        UpdateFlags.Upsert);
    

    weekplanStore 是我的 MongoDB 集合,代码将使用第一个参数中的查询更新找到的文档,如果没有找到,则插入一个新文档。 “诀窍”是使用 UpdateFlags.Upsert 修饰符。

    rawWeekPlan 是插入或更新的对象,具有以下类型:

    private class RawWeekPlan
    {
        public ObjectId id;
        public int weekNumber;
        public WeekPlanEntry[] entries;
    }
    

    并被驱动自动转成bson。

    【讨论】:

    • 它适用于嵌套集合吗?你试过了吗?因为在我的情况下它对他们不起作用
    【解决方案4】:

    您可以使用常规更新命令,但只需将 Upsert 更新标志传递给它

    MongoCollection collection = db.GetCollection("matches");
    var query = new QueryDocument("recordId", recordId);
    
    var update = Update.Set("FirstName", "John").Set("LastName","Doe");
    matchCollection.Update(query, update, UpdateFlags.Upsert, SafeMode.False);
    

    该代码改编自工作应用程序(为清楚起见而缩短)

    【讨论】:

      猜你喜欢
      • 2019-09-07
      • 2011-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多