使用官方 C# 驱动程序在 Mongo DB 中进行更新插入

Posted

技术标签:

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

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

if (_campaignRepo.Exists(camp))

    _campaignRepo.DeleteByIdAndSystemId(camp);


_campaignRepo.Save(camp);

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

【问题讨论】:

【参考方案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);

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

【讨论】:

以上是关于使用官方 C# 驱动程序在 Mongo DB 中进行更新插入的主要内容,如果未能解决你的问题,请参考以下文章

如何将meteor.js db 导入远程mongo

mongodb 查询的用法

Mongo db中的身份验证:如何选择?

在mono中使用c#驱动程序比较mongo集合的两个字段

如何在C#中获取连接字符串中指定的Mongo数据库

GeoSpatial 查询在 mongo shell 中工作,但在 C# 驱动程序中没有过滤