У меня есть коллекция с объектами различной случайной структуры/глубины. Внутри них есть один объект, который я хочу получить в качестве результатов, у которого есть определенная пара ключ/значение, которую я могу использовать для их поиска.
Пример из моей коллекции:
{
"_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
Вы можете сделать что-то вроде:
db.collection.aggregate([
{
$addFields: {
res: {
$function: {
body: "function drill(t, n) {if (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: {$arrayElemAt: ["$res", 0]},
_id: 0
}
},
{
$replaceRoot: {newRoot: "$res"}
}
])
Как видите, на примере этой детской площадки.
Мы можем использовать $function для рекурсивного поиска этого ключа с именем foo и возврата объекта, который его содержит.
Редактировать по вопросу в комментарии:
Вы можете использовать свой код, чтобы манипулировать им в соответствии с вашими потребностями: например в js:
const key = 'foo';
const val = 'bar';
const body = `function drill(t, n) {if (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: {$arrayElemAt: ["$res", 0]}, _id: 0}
},
{
$replaceRoot: {newRoot: "$res"}
}
])
У меня есть один быстрый вопрос относительно приведенного выше кода: - Как мне включить мои параметры поиска db.collection.find( { ... } ) в приведенную выше команду агрегирования? Спасибо.
Ваш запрос является json до тех пор, пока он не будет выполнен. Вы можете отредактировать это json в своем коде в соответствии с вашими потребностями, прежде чем выполнять запрос.
Обновлен ответ, чтобы содержать это.
См. это