使用 MongoDB 和 C# 查询数组中深度嵌套的对象
Query a deeply nested object in arrays using MongoDB and C#
我是 MongoDB 的新手,我已经面临着汗流浃背的挑战。我试图从一个数组中获取一个元素,该数组中的对象位于一个包含对象的数组中(如果这有意义的话)。这是文档的样子以及我想要获得的内容:
所以基本上结构如下:
- 选项菜单
- 选项菜单主题
- 选项菜单项
为了获得我匹配的 OptionMenuItem,使用来自 MongoDB Compass 工具
的聚合管道工具将其拉下来
[{
$unwind: {
path: '$subjects'
}
}, {
$unwind: {
path: '$subjects.items'
}
}, {
$project: {
_id: '$subjects.items._id',
item: '$subjects.items'
}
}, {
$match: {
_id: ObjectId('5e6eaef8ae35a418f4f6dbd4')
}
}]
然后我尝试将其翻译成 C# 但没有成功,这是我目前为止的情况:
var optionMenuItem = await collection.Aggregate()
.Unwind<OptionMenu, OptionMenuSubject>(i => i.Subjects)
.Unwind<OptionMenuSubject, OptionMenuItem>(i => i.Items)
.Match(i => i.Id == id)
.ToListAsync();
如果有人知道我做错了什么或者我该如何解决这个问题,将不胜感激:)
展开未过滤的数据不是一个好主意,因为它会在 mongodb 内存中创建大量数据,您可能会达到 100mb 的聚合管道限制。因此,在展开之前,请尝试始终过滤和缩小记录范围。我相信以下管道会提供您需要的结果:
db.collection.aggregate([
{
$match: {
'subjects.items._id': ObjectId('5e6eaef8ae35a418f4f6dbd4')
}
},
{
$unwind: '$subjects'
},
{
$unwind: '$subjects.items'
},
{
$match: {
'subjects.items._id': ObjectId('5e6eaef8ae35a418f4f6dbd4')
}
},
{
$replaceWith: '$subjects.items'
}
])
这里是 convenient way to execute this pipeline with c#. you can read more about how it works here。
最后我就是这样解决的。这不是我最引以为豪的作品,因为它没有强大的输入功能,但它确实有效:
var collection = Database.GetCollection<BsonDocument>(_collectionName);
var query = await collection.Aggregate()
.Match(i => i["subjects.items._id"] == ObjectId.Parse(id))
.Unwind(i => i["subjects"])
.Unwind(i => i["subjects.items"])
.Match(i => i["subjects.items._id"] == ObjectId.Parse(id))
.ReplaceRoot(i => i["subjects.items"])
.FirstOrDefaultAsync();
我是 MongoDB 的新手,我已经面临着汗流浃背的挑战。我试图从一个数组中获取一个元素,该数组中的对象位于一个包含对象的数组中(如果这有意义的话)。这是文档的样子以及我想要获得的内容:
所以基本上结构如下:
- 选项菜单
- 选项菜单主题
- 选项菜单项
- 选项菜单主题
为了获得我匹配的 OptionMenuItem,使用来自 MongoDB Compass 工具
的聚合管道工具将其拉下来[{
$unwind: {
path: '$subjects'
}
}, {
$unwind: {
path: '$subjects.items'
}
}, {
$project: {
_id: '$subjects.items._id',
item: '$subjects.items'
}
}, {
$match: {
_id: ObjectId('5e6eaef8ae35a418f4f6dbd4')
}
}]
然后我尝试将其翻译成 C# 但没有成功,这是我目前为止的情况:
var optionMenuItem = await collection.Aggregate()
.Unwind<OptionMenu, OptionMenuSubject>(i => i.Subjects)
.Unwind<OptionMenuSubject, OptionMenuItem>(i => i.Items)
.Match(i => i.Id == id)
.ToListAsync();
如果有人知道我做错了什么或者我该如何解决这个问题,将不胜感激:)
展开未过滤的数据不是一个好主意,因为它会在 mongodb 内存中创建大量数据,您可能会达到 100mb 的聚合管道限制。因此,在展开之前,请尝试始终过滤和缩小记录范围。我相信以下管道会提供您需要的结果:
db.collection.aggregate([
{
$match: {
'subjects.items._id': ObjectId('5e6eaef8ae35a418f4f6dbd4')
}
},
{
$unwind: '$subjects'
},
{
$unwind: '$subjects.items'
},
{
$match: {
'subjects.items._id': ObjectId('5e6eaef8ae35a418f4f6dbd4')
}
},
{
$replaceWith: '$subjects.items'
}
])
这里是 convenient way to execute this pipeline with c#. you can read more about how it works here。
最后我就是这样解决的。这不是我最引以为豪的作品,因为它没有强大的输入功能,但它确实有效:
var collection = Database.GetCollection<BsonDocument>(_collectionName);
var query = await collection.Aggregate()
.Match(i => i["subjects.items._id"] == ObjectId.Parse(id))
.Unwind(i => i["subjects"])
.Unwind(i => i["subjects.items"])
.Match(i => i["subjects.items._id"] == ObjectId.Parse(id))
.ReplaceRoot(i => i["subjects.items"])
.FirstOrDefaultAsync();