c# - 如何使用 C# 驱动程序在 MongoDb 中嵌套在字典(文档数组)中的列表中插入值?
问题描述
我有以下课程:
class Parent
{
public ObjectId Id { get; set; }
[BsonDictionaryOptions(Representation = DictionaryRepresentation.ArrayOfDocuments)]
public IDictionary<string, List<Child>> Children { get; set; }
}
class Child { }
我知道想在 Dictionary 的一个条目中添加一个新的 Child:
using MongoDB.Driver;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var collection = new MongoClient("mongodb://localhost:27017")
.GetDatabase("Test").GetCollection<Parent>("Parents");
var parent = new Parent();
collection.InsertOne(parent);
collection.UpdateOne(p => p.Id == parent.Id,
Builders<Parent>.Update.Push(p => p.Children["string1"], new Child()));
}
}
}
我得到一个System.InvalidOperationException
:
无法确定 p => p.Children.get_Item("string1") 的序列化信息。
我设法让它像这样工作:
collection.UpdateOne(p => p.Id == parent.Id && p.Children.Any(a => a.Key == "string1"),
Builders<Parent>.Update.Push($"{nameof(Parent.Children)}.$.v", new Child()));
但这非常难看,只有在条目"string1"
已经存在时才有效。
这可能是相关的:无法确定表达式错误的序列化信息
解决方案
我终于可以得到一些工作。这是我的代码(下面的解释):
class Parent
{
public ObjectId Id;
//Remove the attribute. This field needs to be initialized
public IDictionary<string, List<Child>> Children = new Dictionary<string, List<Child>>();
}
class Child
{
public string ChildName; // This isn't needed
}
class Program
{
static void Main(string[] args)
{
var collection = new MongoClient("mongodb://localhost:27017")
.GetDatabase("Test").GetCollection<Parent>("Parents");
var parent = new Parent();
collection.InsertOne(parent);
collection.UpdateOne(p => p.Id == parent.Id,
Builders<Parent>.Update
.Push(p => p.Children["string1"], new Child {ChildName = "I am the new guy!"}));
}
}
这里有两件事。首先,我删除了该属性。其次,该字段需要用空字典初始化,否则会报错。如果您设置的键尚不存在,将自动创建关联列表。我还向 Child 类添加了一个字段,但这不是必需的,它可以保持为空。
你甚至可以在同一个 $push 中创建多个键:
collection.UpdateOne(p => p.Id == parent.Id,
Builders<Parent>.Update
.Push(p => p.Children["string1"], new Child {ChildName = "I am the new guy!"})
.Push(p => p.Children["string2"], new Child {ChildName = "I am a child in string2!"}));
但是,这很重要,但是,如果您尝试按下相同的键,则只有最后一次按下才会生效。这不起作用:
collection.UpdateOne(p => p.Id == parent.Id,
Builders<Parent>.Update
.Push(p => p.Children["string1"], new Child {ChildName = "I wont be pushed to string1"})
.Push(p => p.Children["string1"], new Child {ChildName = "I will overwrite the previous push"}));
在这些情况下,您必须使用PushEach
并传递一组项目。您可以PushEach
结合Push
:
collection.UpdateOne(p => p.Id == parent.Id,
Builders<Parent>.Update
.PushEach(p => p.Children["string1"], new [] {new Child {ChildName = "I am the first child!"}, new Child {ChildName = "I am the second child!"}})
.Push(p => p.Children["string2"], new Child {ChildName = "I am a child in string2!"}));
让我知道这是否对您有用!
推荐阅读
- arrays - 我有一个图像列表,图像形状是 (50,50,3) 。如何转换为形状的 numpy.ndarray (19929,50,50,3)
- javascript - 第一个标志淡出,但第二个标志没有淡入......向下滚动。我错过了什么?
- gridview - 冻结网格视图标题 (odoo V12)
- java - 为什么 Wildfly 找不到 postgresql 驱动程序
- javascript - 如何自定义 json-server 错误处理
- c++ - 为什么使用 std::sort() )给我垃圾值?
- wordpress - 如何在子文件夹中为 WordPress REST API 配置 nginx?
- c# - 如何读取某个控制台位置存在的字符?
- java - 我需要帮助在 Java 中散列密码
- python - Scrapy - 选择和抓取特定类型的站点地图节点