MongoDB - 从任意深度和 object 结构中获取子文档
MongoDB - get subdocuments from arbitrary depth and object structure
我有一个 collection,其中有 object 个不同的随机 structures/depths。在其中,有一个 object 我想作为我的结果得到,它有一个特定的 key/value 对,我可以用它来找到它们。
我的例子 collection:
{
"_id": ObjectId("123"),
"someKey": "blue",
"children": [
{
"foo": "bar",
"anotherKey": "anotherValue",
"whateverA": 111
}
]
}
{
"_id": ObjectId("456"),
"blahKey": "dog",
"children": [
{
"anotherRandom": "randomValue",
"children": [
{
"moreRandom": "stuffValue",
"children": [
{
"foo": "bar",
"animalKey": "legsValue",
"whateverB": 222
}
]
}
]
}
]
}
我想搜索包含“foo:bar”的子文档,得到如下所示的结果:
{
"foo": "bar",
"anotherKey": "anotherValue",
"whateverA": 111
}
{
"foo": "bar",
"animalKey": "legsValue",
"whateverB": 222
}
然后我可以对结果进行分页。这在 MongoDB 5 中甚至可能吗?
谢谢。
如果我们使用@rickhg12hs
的
您可以这样做:
编辑:已修复以处理未找到的情况(感谢@Jimba 的评论):
db.collection.aggregate([
{
$addFields: {
res: {
$function: {
body: "function drill(t, n) {if (n && n.length > 0){for (let elem of n){if(elem['foo'] && elem['foo'] === 'bar'){t.push(elem);}else {drill(t, elem.children)}}}return t}",
args: [
[],
"$children"
],
lang: "js"
}
}
}
},
{
$project: {
res: {
$cond: [
{$gt: [{$size: "$res"}, 0]},
{$arrayElemAt: ["$res", 0]},
{res: null}
]
},
_id: 0
}
},
{
$match: {res: {$ne: null}}
},
{
$replaceRoot: {newRoot: "$res"}
}
])
如你所见on this playground example。
我们可以使用 $function
递归查找名为 foo
的键和 return 包含它的对象。
根据评论中的一个问题编辑:
您可以根据需要使用您的代码对其进行操作:
例如在 js 中:
const key = 'foo';
const val = 'bar';
const body = `function drill(t, n) {if (n && n.length > 0){for (let elem of n){if(elem[${key}] && elem[${key}] === ${val}){t.push(elem);}else {drill(t, elem.children)}}}return t}`;
db.collection.aggregate([
{
$addFields: {res: {$function: {body, args: [[], "$children"], lang: "js"}}}
},
{
$project: {
res: {
$cond: [
{$gt: [{$size: "$res"}, 0]},
{$arrayElemAt: ["$res", 0]},
{res: null}
]
},
_id: 0
}
},
{
$match: {res: {$ne: null}}
},
{
$replaceRoot: {newRoot: "$res"}
}
])
我有一个 collection,其中有 object 个不同的随机 structures/depths。在其中,有一个 object 我想作为我的结果得到,它有一个特定的 key/value 对,我可以用它来找到它们。
我的例子 collection:
{
"_id": ObjectId("123"),
"someKey": "blue",
"children": [
{
"foo": "bar",
"anotherKey": "anotherValue",
"whateverA": 111
}
]
}
{
"_id": ObjectId("456"),
"blahKey": "dog",
"children": [
{
"anotherRandom": "randomValue",
"children": [
{
"moreRandom": "stuffValue",
"children": [
{
"foo": "bar",
"animalKey": "legsValue",
"whateverB": 222
}
]
}
]
}
]
}
我想搜索包含“foo:bar”的子文档,得到如下所示的结果:
{
"foo": "bar",
"anotherKey": "anotherValue",
"whateverA": 111
}
{
"foo": "bar",
"animalKey": "legsValue",
"whateverB": 222
}
然后我可以对结果进行分页。这在 MongoDB 5 中甚至可能吗?
谢谢。
如果我们使用@rickhg12hs
的您可以这样做:
编辑:已修复以处理未找到的情况(感谢@Jimba 的评论):
db.collection.aggregate([
{
$addFields: {
res: {
$function: {
body: "function drill(t, n) {if (n && n.length > 0){for (let elem of n){if(elem['foo'] && elem['foo'] === 'bar'){t.push(elem);}else {drill(t, elem.children)}}}return t}",
args: [
[],
"$children"
],
lang: "js"
}
}
}
},
{
$project: {
res: {
$cond: [
{$gt: [{$size: "$res"}, 0]},
{$arrayElemAt: ["$res", 0]},
{res: null}
]
},
_id: 0
}
},
{
$match: {res: {$ne: null}}
},
{
$replaceRoot: {newRoot: "$res"}
}
])
如你所见on this playground example。
我们可以使用 $function
递归查找名为 foo
的键和 return 包含它的对象。
根据评论中的一个问题编辑:
您可以根据需要使用您的代码对其进行操作: 例如在 js 中:
const key = 'foo';
const val = 'bar';
const body = `function drill(t, n) {if (n && n.length > 0){for (let elem of n){if(elem[${key}] && elem[${key}] === ${val}){t.push(elem);}else {drill(t, elem.children)}}}return t}`;
db.collection.aggregate([
{
$addFields: {res: {$function: {body, args: [[], "$children"], lang: "js"}}}
},
{
$project: {
res: {
$cond: [
{$gt: [{$size: "$res"}, 0]},
{$arrayElemAt: ["$res", 0]},
{res: null}
]
},
_id: 0
}
},
{
$match: {res: {$ne: null}}
},
{
$replaceRoot: {newRoot: "$res"}
}
])