#mongodb #aggregation-framework #pymongo
#mongodb #агрегация-фреймворк #pymongo
Вопрос:
Я использую Python с pymongo для запроса из базы данных.
У меня есть 3 разные коллекции:
1-й:
# Projects collection
{
"_id": "A",
},
{
"_id": "B",
},
{
"_id": "C"
},
..
2-й:
# Episodes collection
{
"_id": "A/Episode01",
"project": "A",
"name": "Episode01"
},
{
"_id": "A/Episode02",
"project": "A",
"name": "Episode02"
},
{
"_id": "B/Episode01",
"project": "B",
"name": "Episode01"
},
..
3-й:
# Sequences collection
{
"_id": "A/Episode01/Sequence01",
"project": "A",
"episode": "Episode01",
"name": "Sequence01"
},
{
"_id": "A/Episode02/Sequence02",
"project": "A",
"episode": "Episode02",
"name": "Sequence02"
},
{
"_id": "B/Episode01/Sequence01",
"project": "B",
"episode": "Episode01",
"name": "Sequence01"
},
..
Я хочу использовать aggregate для запроса проекта A
и получить все соответствующие ему эпизоды и последовательности, подобные этому:
{
"_id": "A",
"episodes":
[
{
"_id": "A/Episode01",
"project": "A",
"name": "Episode01",
"sequences":
[
{
"_id": "A/Episode01/Sequence01",
"project": "A",
"episode": "Episode01",
"name": "Sequence01"
},
]
},
{
"_id": "A/Episode02",
"project": "A",
"name": "Episode02",
"sequences":
[
{
"_id": "A/Episode02/Sequence02",
"project": "A",
"episode": "Episode02",
"name": "Sequence02"
},
]
},
]
}
Я могу получить правильные эпизоды, но я не уверен, как добавить поле для встраивания для любых совпадающих последовательностей. Возможно ли сделать все это в одном конвейерном запросе?
Прямо сейчас мой запрос выглядит следующим образом:
[
{"$match": {
"_id": "A"}
},
{"$lookup": {
"from": "episodes",
"localField": "_id",
"foreignField": "project",
"as": "episodes"}
},
{"$group": {
"_id": {
"_id": "$_id",
"episodes": "$episodes"}
}}
]
Ответ №1:
Вы можете сделать следующее
- используйте
$match
для сопоставления документа - используйте некоррелированные запросы для объединения двух коллекций. Но обычное объединение также возможно, как вы написали. Это проще, когда мы сталкиваемся с некоторыми сложными ситуациями.
Сценарий Mongo приведен ниже
[
{
"$match": {
"_id": "A"
}
},
{
$lookup: {
from: "Episodes",
let: {
id: "$_id"
},
pipeline: [
{
$match: {
$expr: {
$eq: [
"$project",
"$$id"
]
}
}
},
{
$lookup: {
from: "Sequences",
let: {
epi: "$name"
},
pipeline: [
{
$match: {
$expr: {
$eq: [
"$episode",
"$$epi"
]
}
}
}
],
as: "sequences"
}
}
],
as: "episodes"
}
}
]
Рабочая игровая площадка Mongo
Обновление 01
Использование стандартного поиска
[
{
"$match": {
"_id": "A"
}
},
{
"$lookup": {
"from": "Episodes",
"localField": "_id",
"foreignField": "project",
"as": "episodes"
}
},
{
$unwind: "$episodes"
},
{
"$lookup": {
"from": "Sequences",
"localField": "episodes.name",
"foreignField": "episode",
"as": "episodes.sequences"
}
},
{
$group: {
_id: "$episodes._id",
episodes: {
$addToSet: "$episodes"
}
}
}
]
Рабочая игровая площадка Mongo
Комментарии:
1. Я думаю, что моя версия mongo не поддерживает
let
поиск, так как я на 3.2.3. Прямо сейчас это выдает ошибку$lookup must be strings, let: { id: "$_id" } is type 3
2. Ох. хорошо, тогда у нас будет больше работы со стандартным поиском. Я сделаю и дам вам знать
3. Вау, это, кажется, работает, и мне кажется, что оно намного более читабельно, чем более новая версия. Только одна проблема, которую я вижу, заключается в том, что похоже, что он находит последовательности только по названию эпизода. Могут быть другие проекты с тем же именем, так что возможно ли сопоставить его как с эпизодом, так и с проектом, чтобы предотвратить захват неправильных записей?
4. НЕТ, нет никакого способа, если вы не используете некоррелированный поиск. Что вы можете сделать, так это просто сопоставить и удалить на другом этапе
5. Будет ли использование
$filter
на другом этапе способом удаления любых конфликтующих записей?