将REST API修补到.NET中的部分更新MongoDB

Car*_*mas 3 c# rest updates partial mongodb

我有一个对象

{
  "_id": "testobject",
  "A": "First line",
  "B": "Second line",
  "C": "Third line"
}
Run Code Online (Sandbox Code Playgroud)

我想向我的API发送REST PATCH请求,以仅更新这些属性之一

{
  "_id": "testobject",
  "C": "Forth line"
}
Run Code Online (Sandbox Code Playgroud)

这被解析成一个类

public class SomeObject {
  public string A { get; set; }
  public string B { get; set; }
  public string C { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

现在,我需要更新MongoDB中的现有文档,但仅更新该属性C

我可以为此记录创建一个更新定义

UpdateDefinition<SomeObject> update = Builders<SomeObject>.Update.Set(x => x.C, <value of property C>)
Run Code Online (Sandbox Code Playgroud)

或者我可以对每个属性进行硬编码检查以查看其是否为空

IList<UpdateDefinition<SomeObject>> updates = new List<UpdateDefinition<SomeObject>>();
if (!string.IsNullOrEmpty(C)) {
  updates.Add(UpdateDefinition<SomeObject> update = Builders<SomeObject>.Update.Set(x => x.C, <value of property C>));
}
if (!string.IsNullOrEmpty(C)) {
  updates.Add(UpdateDefinition<SomeObject> update = Builders<SomeObject>.Update.Set(x => x.C, <value of property C>));
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我有许多属性和许多子属性,则可能很快变得非常大。另一个问题是,如果我将属性的值设置为有意为空,则由于它查找字段为非空,因此它根本不会更新记录。

如何在.NET中动态地对MongoDB文档进行部分更新,以使我具有通用的PATCH API调用,该调用可以采用文档具有的任何参数,并且仅更新指定的属性?

小智 5

我建议您避免依赖1.x旧版API,因为2.x也完全支持它,如下面的示例代码所示。

var client = new MongoClient();
var database = client.GetDatabase("test");
var collection = database.GetCollection<BsonDocument>("test");

var changesJson = "{ a : 1, b : 2 }";
var changesDocument = BsonDocument.Parse(changesJson);

var filter = Builders<BsonDocument>.Filter.Eq("_id", 1);

UpdateDefinition<BsonDocument> update = null;
foreach (var change in changesDocument)
{
    if (update == null)
    {
        var builder = Builders<BsonDocument>.Update;
        update = builder.Set(change.Name, change.Value);
    }
    else
    {
        update = update.Set(change.Name, change.Value);
    }
}

//following 3 lines are for debugging purposes only
//var registry = BsonSerializer.SerializerRegistry;
//var serializer = registry.GetSerializer<BsonDocument>();
//var rendered = update.Render(serializer, registry).ToJson();

//you can also use the simpler form below if you're OK with bypassing the UpdateDefinitionBuilder (and trust the JSON string to be fully correct)
update = new BsonDocumentUpdateDefinition<BsonDocument>(new BsonDocument("$set", changesDocument));

var result = collection.UpdateOne(filter, update);
Run Code Online (Sandbox Code Playgroud)

感谢Robert Stam提供的代码示例。


Has*_*san 1

您可以使用

IMongoUpdate updateDoc = new UpdateDocument("$set", doc);
collection.Update(Query.EQ("_id",id), updateDoc);
Run Code Online (Sandbox Code Playgroud)

但是,您应该小心。

如果您首先将文档反序列化为 SomeObject,则所有字段都将获得其默认值(字符串为 null,整数为 0 等)。如果您使用该对象进行更新,则 json 字符串中不存在的字段将更新为其默认值。

如果你使用

var bsonDoc = BsonSerializer.Deserialize<BsonDocument>(jsonString);  
IMongoUpdate updateDoc = new UpdateDocument("$set", bsonDoc);
collection.Update(Query.EQ("_id",id), updateDoc);
Run Code Online (Sandbox Code Playgroud)

数据库上的文档将仅针对 jsonString 中存在的字段进行更新