【问题标题】:Upsert Dictionary in MongoDbMongoDb中的Upsert字典
【发布时间】:2017-01-16 08:56:05
【问题描述】:

据我所知,mongodb 知道Dictionary 是一个对象,它不能做任何与数组相关的操作。我更改了序列化并尝试了各种类型的字典序列化。但没有机会。
所以我将我的字段(字典)(全部)加载到内存中,更新它并将其设置回 mongodb。
有没有办法使用 c# 驱动程序在 mongodb 中 upsert 字典?


我的文档类型:

public class Site
    {
        public string Id { get; set; }
        //[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
        public Dictionary<string,string> Properties { get; set; }
    }

我的更新操作:

public ServiceResult UpdateProperties(string id, Dictionary<string,string> properties)
        {
            var baseList = Collection.Find(m => m.Id == id)
                .Project(s => s.Properties)
                .FirstOrDefault();

            if (baseList == null)
            {
                baseList = properties;
            }
            else
            {
                baseList.Upsert(properties); //update,insert dic by new one
            }

            var filter = Builders<Site>.Filter
                .Eq(m => m.Id, id);

            var update = Builders<Site>.Update
                .Set(m => m.Properties, baseList);

            try
            {
                Collection.UpdateOne(filter, update);

                return ServiceResult.Okay(Messages.ItemUpdated);

            }
            catch (Exception ex)
            {
                return ServiceResult.Exception(ex);
            }    
        }

非常感谢您提供的任何帮助。


消歧:

public static class DictionaryExtensions
    {
        public static void Upsert<TKey, TValue>(this Dictionary<TKey, TValue> source, 
                                          Dictionary<TKey, TValue> newOne)
        {
            foreach (var item in newOne)
            {
                source[item.Key] = item.Value;
            }
        }
    }

【问题讨论】:

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


    【解决方案1】:

    您可以浏览所有要更新/插入的属性并为每个属性执行此操作:

    UpdateDefinition<Site> upsert = null;
    if (properties.Any())
    {
        var firstprop = properties.First();
        upsert = Builders<Site>.Update.Set(nameof(Site.Properties) + "." + firstprop.Key, 
                                   firstprop.Value);
    
        foreach (var updateVal in properties.Skip(1))
        {
            upsert = upsert.Set(nameof(Site.Properties) + "." + updateVal.Key, 
                                              updateVal.Value);
        }
    
        collection.UpdateOne(r => r.Id == "YourId", upsert, 
                                                   new UpdateOptions { IsUpsert = true });
    }
    

    以前版本的答案,有多个更新:

    foreach (var updateVal in properties)
    {
        collection.UpdateOne(r => r.Id == "YourId", 
            Builders<Site>.Update.Set( nameof(Site.Properties)+ "." + updateVal.Key, 
                                       updateVal.Value), 
                                       new UpdateOptions { IsUpsert = true});
    }
    

    注意,这只会添加新的键/值或更新现有的,这不会删除任何东西。

    【讨论】:

    • 它有效。真是个好人。让我们看看有什么建议可以避免多连接(用于更新)。到目前为止,这是我接受的答案。
    • 我已经更新了答案,只执行一次更新:)
    • 像魅力一样工作。感谢您的时间和考虑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 2014-05-05
    • 1970-01-01
    • 2013-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多