MongoDB C#仅更新非空字段

时间:2016-08-12 12:41:53

标签: c# mongodb

我有一份文件,例如

{
    "_id": "ABC",
    "name": "Bob",
    "age": 42
}

我有两个在不同时间分开运行的功能。功能A更新名称和功能B更新年龄。这两个函数都调用外部休息服务,该服务根据服务返回名称或年龄。

我有一个映射到mongo文档的类

public class Person {
    [BsonId]
    public string Id { get; set; }

    [BsonElement("name")]
    public string Name { get; set; }

    [BsonElement("age")]
    public int Age { get; set; }
}

函数A将仅填充此类的Id和Name属性,而函数B将填充Id和Age属性。

如何通过从函数B传递Person对象来更新mongo文档,以便它保留函数A的现有值?

我知道你可以做Builders<Person>.Update.Set(x => x.Age, <new_age>)但是我希望我的代码更加动态,所以如果我添加另一个名为'Phone'的字段,我可以调用一个只更新字段的泛型方法一个值,不是null。

1 个答案:

答案 0 :(得分:0)

仅将要更新的元素添加到新的BsonDocument中,以创建更新定义。

private static void SetUpdatableElements(BsonDocument bdoc, BsonDocument updateDefintion, HashSet<string>() excluded = null, string parentName = "")
{
    var excluded = excluded ?? new HashSet<string>()
    parentName = !string.IsNullOrWhiteSpace(parentName) ? $"{parentName}." : "";
    foreach (var item in bdoc)
    {
        if (item.Value.IsObjectId || // skip _id                     
            item.Value.IsBsonNull || // skip properties with null values
            excluded.Contains(item.Name)) // skip other properties that should not be updated
        {
            continue;
        }
        if (!item.Value.IsBsonDocument) // to avoid override nested objects)
        {
            updateDefintion = updateDefintion.Add($"{parentName}{item.Name}", item.Value);
            continue;
        }
        // recursively set nested elements to avoid overriding the full object
        SetUpdatableElements(item.Value.ToBsonDocument(), updateDefintion, item.Name);
    }
}

来电者:

var person = new Person() { Id = "ABC", Name = "bob", Age:42, Phone="123 456 7890"}
var updateDefintion = new BsonDocument();
var bDoc = person.ToBsonDocument();
SetUpdatableElements(person.ToBsonDocument(), updateDefintion, new HashSet<string>(nameof(person.Name)))
collection.UpdateOneAsync<Person>(p => p.Id == person.Id, new BsonDocument("$set", updateDefintion));

最后,您的updateDefinition应该类似于:

{ {
    "$set": {
        "age": 42
        "phone": "123 456 7890"
    }
} }