欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

记一次Mongodb数据库更新操作之更新为数组或者对象

程序员文章站 2022-03-19 10:22:01
一直以来都是更新为一些简单的基础类型,直到有一天写了一个覆盖某一个字段(这个字段为数组)的更新操作。出问题了,数据库中出现了_t,_v……有点懵了。当然如果我们更新的时候设置类型是不会出现这个问题的,出现这种问题的一个前提是我们将数组赋值给了object类型的变量;由于时间关系问了一下同事,她给出了 ......

  一直以来都是更新为一些简单的基础类型,直到有一天写了一个覆盖某一个字段(这个字段为数组)的更新操作。出问题了,数据库中出现了_t,_v……有点懵了。当然如果我们更新的时候设置类型是不会出现这个问题的,出现这种问题的一个前提是我们将数组赋值给了object类型的变量;由于时间关系问了一下同事,她给出了解决办法:mongodb的驱动去反序列化一下。问题就这么解决了,今天有时间记录一下,在写示例代码的时候发现更新对象也不行。

  先看一下我们的数据,以及更新之后的截图:

/* 1 */
{
    "_id" : "1",
    "name" : "ddz001",
    "age" : 10,
    "valid" : true,
    "createdate" : isodate("2020-03-28t05:59:43.841z"),
    "lastupdatedtime" : isodate("2020-03-28t05:59:43.841z"),
    "details" : {
        "height" : 169.5,
        "weight" : 70.5,
        "married" : true
    },
    "bookmarks" : [ 
        {
            "title" : "百度一下",
            "url" : "https://www.baidu.com/"
        }, 
        {
            "title" : "必应",
            "url" : "https://cn.bing.com/"
        }
    ]
}

/* 2 */
{
    "_id" : "2",
    "name" : "ddz002",
    "age" : 20,
    "valid" : true,
    "createdate" : isodate("2020-03-28t05:59:43.841z"),
    "lastupdatedtime" : isodate("2020-03-28t05:59:43.841z"),
    "details" : {
        "height" : 170.5,
        "weight" : 71.5,
        "married" : true
    },
    "bookmarks" : [ 
        {
            "title" : "搜狗搜索",
            "url" : "https://www.baidu.com/"
        }, 
        {
            "title" : "多吉搜索",
            "url" : "https://www.dogedoge.com/"
        }
    ]
}

记一次Mongodb数据库更新操作之更新为数组或者对象

  为什么会出现上图中的问题,打印了一下updatedefinition生成的shell命令,你会发现是这样的,

记一次Mongodb数据库更新操作之更新为数组或者对象

  后面直接用同事的方法试了一下,再查看生成的语句就没问题了

记一次Mongodb数据库更新操作之更新为数组或者对象

  既然updatedefinition可以转成字符串,并且他同样可以直接赋值为字符串,例如:updatedefinition<bsondocument> updatedefinition = ""; ,那么我想了一下我们直接拼这个字符串应该就没问题了,当然这种我没有测试啊!

  这里面还会遇到一个问题就是怎么判断一个object的真实类型,这里仅仅需要知道他是不是对象或者数组(这里是泛指所有的)。可能真的有点菜,不知道如果判断。看了一下官方文档:type类,也没有找到,最后还是使用比较笨的方法:先序列化为字符串之后在反序列化为object,他会告诉你类型的。最后一个问题是这个解决问题的办法是不是最优的,感觉有点浪费……如果有哪位大神知道高效的方式,请不吝赐教,再次感谢。

  最后看一下我的示例代码:

using mongodb.bson;
using mongodb.bson.serialization;
using mongodb.bson.serialization.attributes;
using mongodb.driver;
using system;
using system.collections.generic;
using system.linq;
using system.text.encodings.web;
using system.text.json;

namespace ddz.mongodbupdatearraytest
{
    class program
    {
        static void main(string[] args)
        {
            //清空表(新增之前先清空)、批量添加(初始化一些数据)、查询操作
            //deletemanybatchaddfind();

            //更新数据和object测试
            //updatearrayorobject();

            #region 寻找解决办法
            var _client = new mongoclient("mongodb://localhost:27017");
            var _database = _client.getdatabase("formbuilder");
            var _collection = _database.getcollection<bsondocument>("updatearraytest");
            datetime dtnow2 = datetime.now;
            list<keyvaluemodel> keyvaluemodels = new list<keyvaluemodel>()
            {
                new keyvaluemodel(){ key="name",value ="ddz001+++" },
                new keyvaluemodel(){ key="age",value = 11 },
                new keyvaluemodel(){ key="valid",value = false },
                new keyvaluemodel(){ key="lastupdatedtime",value=dtnow2 },
                new keyvaluemodel(){ key="details",value = new otherinfomodel(){ height=179.5f,weight=80.5f,married=false } },
                new keyvaluemodel()
                {
                    key="bookmarks",value = new list<bookmarkmodel>()
                    {
                        new bookmarkmodel() { title="yandex",url="https://yandex.com/" },
                        new bookmarkmodel() { title="秘迹搜索",url="https://mijisou.com/" }
                    }
                }
            };
            var tempupdateobj = new
            {
                name = "ddz001+++",
                age = 11,
                valid = false,
                lastupdatedtime = dtnow2,
                details = new otherinfomodel() { height = 179.5f, weight = 80.5f, married = false },
                bookmarks = new list<bookmarkmodel>()
                    {
                        new bookmarkmodel() { title="yandex",url="https://yandex.com/" },
                        new bookmarkmodel() { title="秘迹搜索",url="https://mijisou.com/" }
                    }
            };
            var tempupdatedic = new dictionary<string, object>() 
            {
                { "name", "ddz001+++"},
                { "age", ""},
                { "valid", false},
                { "lastupdatedtime", dtnow2},
                { "details", new otherinfomodel() { height = 179.5f, weight = 80.5f, married = false }},
                { "bookmarks", new list<bookmarkmodel>()
                    {
                        new bookmarkmodel() { title="yandex",url="https://yandex.com/" },
                        new bookmarkmodel() { title="秘迹搜索",url="https://mijisou.com/" }
                    }
                },
            };

            if (keyvaluemodels.any())
            {
                var updatedefinitions = new list<updatedefinition<bsondocument>>();
                foreach (var item in keyvaluemodels)
                {
                    if (item.value == null)
                    {
                        updatedefinitions.add(builders<bsondocument>.update.set(item.key, bsonnull.value));
                        continue;
                    }
                    string tempvalueforstr = jsonserializer.serialize(item.value);
                    var tempvalueforobj = jsonserializer.deserialize<object>(tempvalueforstr);
                    var tempvaluetype = ((jsonelement)tempvalueforobj).valuekind;
                    switch (tempvaluetype)
                    {
                        case jsonvaluekind.object:
                        case jsonvaluekind.array:
                            {
                                updatedefinitions.add(builders<bsondocument>.update.set(item.key, bsonserializer.deserialize<object>(tempvalueforstr)));
                                break;
                            }
                        default:
                            {
                                updatedefinitions.add(builders<bsondocument>.update.set(item.key, item.value));
                                break;
                            }
                    }
                }
                var updatedefinition = builders<bsondocument>.update.combine(updatedefinitions);
                string tempupdatestr = getjsonstingbyupdatedefinition(updatedefinition);
                //var modifiedcount1 = _collection.updatemany(builders<bsondocument>.filter.eq("_id", "1"), updatedefinition).modifiedcount;
                string tempupdatestrfromobj = "{ \"$set\" : " + tempupdateobj.tojson() + " }";
                //你会发现这个字符串中也是包含_t和_v,因为字典的值类型为object
                //驱动可能也是这么调用的,当然我没看源码
                string tempupdatestrfromdictionary = "{ \"$set\" : " + tempupdatedic.tojson() + " }";
                //var modifiedcount2 = _collection.updatemany(builders<bsondocument>.filter.eq("_id", "1"), tempupdatestrfromobj).modifiedcount;
            }
            #endregion

            console.writeline("hello world!");
        }

        /// <summary>
        /// 清空表(新增之前先清空)、批量添加(初始化一些数据)、查询操作
        /// </summary>
        static void deletemanybatchaddfind()
        {
            var _client = new mongoclient("mongodb://localhost:27017");
            var _database = _client.getdatabase("formbuilder");
            var _collection = _database.getcollection<updatearraytestmodel>("updatearraytest");
            //  如果表不存在不报错
            var delcount = _collection.deletemany(builders<updatearraytestmodel>.filter.empty).deletedcount;
            var dtnow = datetime.now;
            list<updatearraytestmodel> initupdatearraytestmodels = new list<updatearraytestmodel>()
            {
                new updatearraytestmodel()
                {
                    id="1",name="ddz001",age=10,valid=true,createdate=dtnow,lastupdatedtime=dtnow,
                    details=new otherinfomodel(){ height=169.5f, weight=70.5f, married=true },
                    bookmarks=new list<bookmarkmodel>()
                    {
                        new bookmarkmodel(){ title="百度一下",url="https://www.baidu.com/" },
                        new bookmarkmodel(){ title="必应",url="https://cn.bing.com/" }
                    }
                },
                new updatearraytestmodel()
                {
                    id="2",name="ddz002",age=20,valid=true,createdate=dtnow,lastupdatedtime=dtnow,
                    details=new otherinfomodel(){ height=170.5f, weight=71.5f, married=true },
                    bookmarks=new list<bookmarkmodel>()
                    {
                        new bookmarkmodel(){ title="搜狗搜索",url="https://www.baidu.com/" },
                        new bookmarkmodel(){ title="多吉搜索",url="https://www.dogedoge.com/" }
                    }
                }
            };
            _collection.insertmany(initupdatearraytestmodels);
            
            //这里的中文还没有问题
            var queryresult = _collection.find(builders<updatearraytestmodel>.filter.empty).tolist();
            //这里的中文就变成了unicode,你可以试一试序列化选项
            var queryresultstr = jsonserializer.serialize(queryresult);
            jsonserializeroptions jsonserializeroptions = new jsonserializeroptions{ encoder = javascriptencoder.unsaferelaxedjsonescaping };
            var queryresultstr2 = jsonserializer.serialize(queryresult, jsonserializeroptions);
        }

        /// <summary>
        /// 更新数据和object测试
        /// </summary>
        static void updatearrayorobject()
        {
            //  这里也遇到了同样的问题
            //      1、https://jira.mongodb.org/browse/csharp-1984
            //  其他相关
            //      1、https://www.codeproject.com/tips/1268019/mongodb-csharp-how-to-deserialize-a-json-containin
            //      2、https://blog.csdn.net/mzl87/article/details/85488319
            var _client = new mongoclient("mongodb://localhost:27017");
            var _database = _client.getdatabase("formbuilder");
            var _collection = _database.getcollection<bsondocument>("updatearraytest");
            list<keyvaluemodel> keyvaluemodels = new list<keyvaluemodel>()
            {
                new keyvaluemodel(){ key="name",value ="ddz001+++" },
                new keyvaluemodel(){ key="age",value = 11 },
                new keyvaluemodel(){ key="valid",value = false },
                new keyvaluemodel(){ key="lastupdatedtime",value=datetime.now },
                new keyvaluemodel(){ key="details",value= new otherinfomodel(){ height=179.5f,weight=80.5f,married=false } },
                new keyvaluemodel()
                {
                    key="bookmarks",value = new list<bookmarkmodel>()
                    {
                        new bookmarkmodel() { title="yandex",url="https://yandex.com/" },
                        new bookmarkmodel() { title="秘迹搜索",url="https://mijisou.com/" }
                    }
                }
            };
            if (keyvaluemodels.any())
            {
                var updatedefinitions = new list<updatedefinition<bsondocument>>();
                foreach (var item in keyvaluemodels)
                {
                    updatedefinitions.add(builders<bsondocument>.update.set(item.key, item.value));
                }
                var updatedefinition = builders<bsondocument>.update.combine(updatedefinitions);
                string tempupdatestr = getjsonstingbyupdatedefinition(updatedefinition);
                //var modifiedcount = _collection.updatemany(builders<bsondocument>.filter.eq("_id", "1"), updatedefinition).modifiedcount;
            }
        }

        /// <summary>
        /// 将updatedefinition转为shell字符串
        /// </summary>
        /// <typeparam name="t"></typeparam>
        /// <param name="updatedefinition"></param>
        /// <returns></returns>
        static string getjsonstingbyupdatedefinition<t>(updatedefinition<t> updatedefinition)
        {
            //  参考网址:
            //  https://qa.1r1g.com/sf/ask/2243338471/
            if (updatedefinition == null) return null;
            //updatedefinition.render(_collection.documentserializer,_collection.settings.serializerregistry).tostring()
            return updatedefinition.render(bsonserializer.serializerregistry.getserializer<t>(), bsonserializer.serializerregistry).tostring();
        }
    }

    public class updatearraytestmodel
    {
        private string _id { get; set; }

        /// <summary>
        /// 主键id
        /// </summary>
        public string id { set => this._id = value; get => _id; }

        /// <summary>
        /// 姓名
        /// </summary>
        public string name { get; set; }

        /// <summary>
        /// 年龄
        /// </summary>
        public int age { get; set; }

        /// <summary>
        /// 是否有效
        /// </summary>
        public bool valid { get; set; } = true;

        /// <summary>
        /// 创建时间
        /// </summary>
        [bsondatetimeoptions(kind = datetimekind.unspecified)]
        public datetime createdate { get; set; }

        /// <summary>
        /// 最后一次更新时间
        /// </summary>
        [bsondatetimeoptions(kind = datetimekind.unspecified)]
        public datetime lastupdatedtime { get; set; }

        /// <summary>
        /// 其他详细信息
        /// </summary>
        public otherinfomodel details { get; set; }

        /// <summary>
        /// 我的书签
        /// </summary>
        public ienumerable<bookmarkmodel> bookmarks { get; set; }
    }

    public class otherinfomodel
    {
        public float height { get; set; }
        public float weight { get; set; }
        public bool married { get; set; } = true;
    }

    public class bookmarkmodel
    {
        public string title { get; set; }
        public string url { get; set; }
    }

    public class keyvaluemodel
    {
        public string key { get; set; }
        public object value { get; set; }
    }
}