一直以来都是更新为一些简单的基础类型,直到有一天写了一个覆盖某一个字段(这个字段为数组)的更新操作。出问题了,数据库中出现了_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; } } }