Получить список идентификаторов дочерних элементов, в которых отсутствует тег родительского элемента в MongoDB

#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. Это именно то, что я искал, большое вам спасибо!