#mongodb #mongoose #mongodb-query #aggregation-framework
#mongodb #mongoose #mongodb-запрос #агрегация-фреймворк
Вопрос:
Я хочу получить все элементы (или лучшие идентификаторы элементов), в которых отсутствуют теги.
Если дочерний элемент пропускает тег своего родительского элемента, он должен быть выведен.
Документы выглядят следующим образом:
[
{
id: 1,
tags: [
"a",
"b"
],
childs: [
2,
3
]
},
{
id: 2,
tags: [
"a"
],
childs: []
},
{
id: 3,
tags: [],
childs: []
},
{
id: 4,
tags: [
"c"
],
childs: [
5
]
},
{
id: 5,
tags: [
"c"
],
childs: []
},
{
id: 6,
tags: [
"b"
],
childs: [
5
]
},
{
id: 7,
tags: [],
childs: []
},
]
Теперь я хочу выполнить поиск по имени тега, чтобы получить элементы с отсутствующим тегом.
Желаемый результат должен выглядеть следующим образом:
Проверьте наличие тега «a»:
{
id: 3,
...
}
or
{
ids: [3]
}
Проверьте наличие тега «b»:
{
id: 2,
...
},
{
id: 3,
...
}
or
{
ids: [2, 3]
}
Я попробовал агрегацию с помощью функции поиска и конвейера, но она не сработала.
[{
$match: {
tags: "a",
childs: {
$ne: []
}
}
}, {
$lookup: {
from: 'collection1',
localField: 'childs',
foreignField: 'id',
as: 'childs_items',
pipeline: [{
$matching : {
"tags": {
$nin: "a"
}
}
}]
}
}]
Каков был бы наилучший подход?
РЕДАКТИРОВАТЬ: изменены теги примеров документов последних двух документов на «c» EDIT2: добавлены данные примера
Комментарии:
1. Спасибо за ваше предложение, но это не тот точный результат, который я ищу. Я отредактировал сообщение, чтобы прояснить проблему. Набор данных содержит n разных тегов, и только если у родителя есть тег, он также нужен дочернему элементу.
Ответ №1:
Возможно, будут другие простые способы, но это ваш исправленный запрос,
$match
условия как обычно,$lookup
с помощью конвейера определите переменную дляchilds
доступа к внутреннему поиску$match
условия,childs
совпадают или нет, теги не равны указанному символу$project
чтобы создатьids
массив, используя$reduce
db.collection.aggregate([
{
$match: {
tags: "b", // add your search
childs: { $ne: [] }
}
},
{
$lookup: {
from: "collection",
let: { childs: "$childs" },
as: "ids",
pipeline: [
{
$match: {
$expr: { $in: ["$id", "$$childs"] },
tags: { $ne: "b" } // add your search
}
}
]
}
},
{
$project: {
id: 1,
ids: {
$reduce: {
input: "$ids",
initialValue: [],
in: { $concatArrays: ["$$value", ["$$this.id"]] }
}
}
}
}
])
Вы можете использовать свое последнее редактирование, $unwind
а затем $group
после $lookup в приведенном выше примере удалить $project
этап,
{ $unwind: "$ids" },
{
$group: {
_id: null,
ids: { $push: "$ids.id" }
}
}
Комментарии:
1. Потрясающе, работает действительно хорошо! Спасибо! Небольшой вопрос: что мне нужно сделать, чтобы объединить идентификаторы результатов в один массив? (В настоящее время для каждого родителя будет создан новый результирующий объект. Я отредактировал свои исходные документы)
2. вы можете сделать что-то вроде этого , я удалил $project, добавил $ unwind и $ group, group by null и идентификаторы push в массиве ids
3. Это именно то, что я искал, большое вам спасибо!