记一次Mongodb数据库更新操作之更新为数组或者对象
一直以来都是更新为一些简单的基础类型,直到有一天写了一个覆盖某一个字段(这个字段为数组)的更新操作。出问题了,数据库中出现了_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/" } ] }示例数据
为什么会出现上图中的问题,打印了一下UpdateDefinition生成的shell命令,你会发现是这样的,
后面直接用同事的方法试了一下,再查看生成的语句就没问题了
既然UpdateDefinition可以转成字符串,并且他同样可以直接赋值为字符串,例如: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示例代码("UpdateArrayTest"); DateTime dtNow2 = DateTime.Now; List keyValueModels = new List () { 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 () { 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 () { 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 () { new BookmarkModel() { Title="Yandex",Url="https://yandex.com/" }, new BookmarkModel() { Title="秘迹搜索",Url="https://mijisou.com/" } } }, }; if (keyValueModels.Any()) { var updateDefinitions = new List >(); foreach (var item in keyValueModels) { if (item.Value == null) { updateDefinitions.Add(Builders .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 .Update.Set(item.Key, BsonSerializer.Deserialize<object>(tempValueForStr))); break; } default: { updateDefinitions.Add(Builders .Update.Set(item.Key, item.Value)); break; } } } var updateDefinition = Builders .Update.Combine(updateDefinitions); string tempUpdateStr = GetJsonStingByUpdateDefinition(updateDefinition); //var modifiedCount1 = _collection.UpdateMany(Builders .Filter.Eq("_id", "1"), updateDefinition).ModifiedCount; string tempUpdateStrFromObj = "{ \"$set\" : " + tempUpdateObj.ToJson() + " }"; //你会发现这个字符串中也是包含_t和_v,因为字典的值类型为object //驱动可能也是这么调用的,当然我没看源码 string tempUpdateStrFromDictionary = "{ \"$set\" : " + tempUpdateDic.ToJson() + " }"; //var modifiedCount2 = _collection.UpdateMany(Builders.Filter.Eq("_id", "1"), tempUpdateStrFromObj).ModifiedCount; } #endregion Console.WriteLine("Hello World!"); } ////// 清空表(新增之前先清空)、批量添加(初始化一些数据)、查询操作 /// static void DeleteManyBatchAddFind() { var _client = new MongoClient("mongodb://localhost:27017"); var _database = _client.GetDatabase("FormBuilder"); var _collection = _database.GetCollection ("UpdateArrayTest"); // 如果表不存在不报错 var delCount = _collection.DeleteMany(Builders .Filter.Empty).DeletedCount; var dtNow = DateTime.Now; List initUpdateArrayTestModels = new List () { 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 () { 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 () { new BookmarkModel(){ Title="搜狗搜索",Url="https://www.baidu.com/" }, new BookmarkModel(){ Title="多吉搜索",Url="https://www.dogedoge.com/" } } } }; _collection.InsertMany(initUpdateArrayTestModels); //这里的中文还没有问题 var queryResult = _collection.Find(Builders .Filter.Empty).ToList(); //这里的中文就变成了unicode,你可以试一试序列化选项 var queryResultStr = JsonSerializer.Serialize(queryResult); JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions{ Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; var queryResultStr2 = JsonSerializer.Serialize(queryResult, jsonSerializerOptions); } /// /// 更新数据和Object测试 /// 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 ("UpdateArrayTest"); List keyValueModels = new List () { 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 () { new BookmarkModel() { Title="Yandex",Url="https://yandex.com/" }, new BookmarkModel() { Title="秘迹搜索",Url="https://mijisou.com/" } } } }; if (keyValueModels.Any()) { var updateDefinitions = new List >(); foreach (var item in keyValueModels) { updateDefinitions.Add(Builders .Update.Set(item.Key, item.Value)); } var updateDefinition = Builders .Update.Combine(updateDefinitions); string tempUpdateStr = GetJsonStingByUpdateDefinition(updateDefinition); //var modifiedCount = _collection.UpdateMany(Builders .Filter.Eq("_id", "1"), updateDefinition).ModifiedCount; } } ////// 将UpdateDefinition转为shell字符串 /// /// /// /// static string GetJsonStingByUpdateDefinition (UpdateDefinition 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 (), BsonSerializer.SerializerRegistry).ToString(); } } public class UpdateArrayTestModel { private string _id { get; set; } /// /// 主键ID /// public string Id { set => this._id = value; get => _id; } /// /// 姓名 /// public string Name { get; set; } /// /// 年龄 /// public int Age { get; set; } /// /// 是否有效 /// public bool Valid { get; set; } = true; /// /// 创建时间 /// [BsonDateTimeOptions(Kind = DateTimeKind.Unspecified)] public DateTime CreateDate { get; set; } /// /// 最后一次更新时间 /// [BsonDateTimeOptions(Kind = DateTimeKind.Unspecified)] public DateTime LastUpdatedTime { get; set; } /// /// 其他详细信息 /// public OtherInfoModel Details { get; set; } /// /// 我的书签 /// public IEnumerable 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; } } }