Record an update of Mongodb database to array or object
Keywords:
C#
MongoDB
shell
JSON
Database
It has been updated to some simple basic types until one day an update operation covering a certain field (this field is an array) was written. There is a problem. There is a problem in the database A little confused. Of course, if we set the type when updating, this problem will not occur. One of the preconditions for this problem is that we assign the array to the variable of object type. Because of the time relationship, she asked her colleagues, and she gave the solution: the mongodb driver should be de serialized. That's how the problem is solved. I have time to record it today. I found that updating objects is not good when I wrote the sample code.
Let's take a look at our data and the updated screenshot:
/* 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" : "Use Baidu Search",
"Url" : "https://www.baidu.com/"
},
{
"Title" : "Bing Ying",
"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" : "Sogou search",
"Url" : "https://www.baidu.com/"
},
{
"Title" : "Dodge search",
"Url" : "https://www.dogedoge.com/"
}
]
}
Example data
Why do you have the problem in the figure above? Print the shell command generated by UpdateDefinition, and you will find it is like this,
After that, I'll try my colleague's method, and then check the generated statements
Since UpdateDefinition can be converted to a string, and it can also be directly assigned to a string, for example: UpdateDefinition < bsondocument > UpdateDefinition = ""; then I think it's OK for us to spell this string directly. Of course, I haven't tested this kind of string!
One of the problems we will encounter is how to judge the real type of an object. Here we just need to know whether it is an object or an array (in general, all of them). May really order, do not know if the judgment. Take a look at the official documents: Class Type , we didn't find it, and finally we used a rather stupid method: first serialize it as a string, then deserialize it as an object, and he will tell you the type. The last question is whether the solution is the best. It's a bit wasteful If any great God knows the efficient way, please do not hesitate to give me your advice. Thank you again.
Finally, take a look at my sample code:
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.Json;
namespace DDZ.MongodbUpdateArrayTest
{
class Program
{
static void Main(string[] args)
{
//Clear table (clear before adding), batch add (initialize some data), query operation
//DeleteManyBatchAddFind();
//Update data and Object test
//UpdateArrayOrObject();
#region Find a solution
OtherInfoModel otherInfo = null;
List<BookmarkModel> bookmarks = null;
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="DetailsNull",Value = otherInfo },
new KeyValueModel()
{
Key="Bookmarks",Value = new List<BookmarkModel>()
{
new BookmarkModel() { Title="Yandex",Url="https://yandex.com/" },
new BookmarkModel() { Title="Secret search",Url="https://mijisou.com/" }
}
},
new KeyValueModel(){ Key="BookmarksNull",Value = bookmarks },
};
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);
}
#endregion
Console.WriteLine("Hello World!");
}
/// <summary>
/// Clear table (clear before adding), batch add (initialize some data), query operation
/// </summary>
static void DeleteManyBatchAddFind()
{
var _client = new MongoClient("mongodb://localhost:27017");
var _database = _client.GetDatabase("FormBuilder");
var _collection = _database.GetCollection<UpdateArrayTestModel>("UpdateArrayTest");
// If the table does not exist, no error will be reported
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="Use Baidu Search",Url="https://www.baidu.com/" },
new BookmarkModel(){ Title="Bing Ying",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="Sogou search",Url="https://www.baidu.com/" },
new BookmarkModel(){ Title="Dodge search",Url="https://www.dogedoge.com/" }
}
}
};
_collection.InsertMany(initUpdateArrayTestModels);
var queryResult = _collection.Find(Builders<UpdateArrayTestModel>.Filter.Empty).ToList();
var queryResultStr = JsonSerializer.Serialize(queryResult);
}
/// <summary>
/// Update data and Object test
/// </summary>
static void UpdateArrayOrObject()
{
// The same thing happened here
// 1,https://jira.mongodb.org/browse/CSHARP-1984
// Other related
// 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="Secret search",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>
/// take UpdateDefinition Turn to shell Character string
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="updateDefinition"></param>
/// <returns></returns>
static string GetJsonStingByUpdateDefinition<T>(UpdateDefinition<T> updateDefinition)
{
// Reference website:
// 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>
/// Primary key ID
/// </summary>
public string Id { set => this._id = value; get => _id; }
/// <summary>
/// Full name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Age
/// </summary>
public int Age { get; set; }
/// <summary>
/// Is it effective?
/// </summary>
public bool Valid { get; set; } = true;
/// <summary>
/// Creation time
/// </summary>
[BsonDateTimeOptions(Kind = DateTimeKind.Unspecified)]
public DateTime CreateDate { get; set; }
/// <summary>
/// Last update time
/// </summary>
[BsonDateTimeOptions(Kind = DateTimeKind.Unspecified)]
public DateTime LastUpdatedTime { get; set; }
/// <summary>
/// Other details
/// </summary>
public OtherInfoModel Details { get; set; }
/// <summary>
/// My Bookmarks
/// </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; }
}
}
Sample code