一直以來都是更新為一些簡單的基礎類型,直到有一天寫了一個覆蓋某一個欄位(這個欄位為數組)的更新操作。出問題了,資料庫中出現了_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/" } ] }示例數據
為什麼會出現上圖中的問題,列印了一下UpdateDefinition生成的shell命令,你會發現是這樣的,
後面直接用同事的方法試了一下,再查看生成的語句就沒問題了
既然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; } } }示例代碼