#javascript #arrays #mongodb #aggregation-framework
Вопрос:
У меня возникла проблема с созданием count
элементов, возвращаемых из массива, без учета или использования этих полей в моем объединении.
Структура данных выглядит следующим образом:
[
{
"_id": "1",
"title": "Vanella Icream",
"contain": "sugar",
"details": [
{
"flavour": "Vanella"
},
{
"weight": "10KG"
},
{
"sugar": "15KG"
}
]
},
{
"_id": "2",
"title": "Pretzels",
"contain": "salt",
"details": [
{
"flavour": "Wheat"
},
{
"weight": "10KG"
},
{
"sugar": "15KG"
}
]
},
{
"_id": "3",
"title": "Rasmalai Icream",
"contain": "sugar",
"details": [
{
"flavour": "Vanella"
},
{
"weight": "15KG"
},
{
"sugar": "12KG"
}
]
},
{
"_id": "4",
"title": "Vanella Icream",
"contain": "sugar",
"details": [
{
"flavour": "Vanella"
},
{
"weight": "15KG"
},
{
"sugar": "12KG"
}
]
}
]
Вывод, который я хочу:
[
{
"details": {
"flavour": {
"Vanella": 3, //Number of times Vanella present in each document.
"Wheat": 1,
},
"weight": {
"10KG": 2,
"15KG": 2
},
"sugar": {
"12KG": 2,
"15KG": 2
}
}
}
]
Запрос:
db.collection.aggregate([
{
"$unwind": {
"path": "$details"
}
},
{
"$replaceRoot": {
"newRoot": {
"$mergeObjects": [
"$details",
"$ROOT"
]
}
}
},
{
"$facet": {
"flavour": [
{
"$group": {
"_id": "$flavour",
"sum": {
"$sum": 1
}
}
},
{
"$addFields": {
"flavour": "$_id"
}
},
{
"$project": {
"_id": 0
}
}
],
"weight": [
{
"$group": {
"_id": "$weight",
"sum": {
"$sum": 1
}
}
},
{
"$addFields": {
"weight": "$_id"
}
},
{
"$project": {
"_id": 0
}
}
]
}
},
{
"$addFields": {
"flavour": {
"$reduce": {
"input": {
"$filter": {
"input": {
"$map": {
"input": "$flavour",
"as": "w",
"in": {
"$cond": [
{
"$ne": [
"$w.flavour",
null
]
},
{
"$let": {
"vars": {
"o": [
[
"$w.flavour",
"$w.sum"
]
]
},
"in": {
"$arrayToObject": "$o"
}
}
},
null
]
}
}
},
"as": "f",
"cond": {
"$ne": [
"$f",
null
]
}
}
},
"initialValue": {},
"in": {
"$let": {
"vars": {
"d": "$value",
"p": "$this"
},
"in": {
"$mergeObjects": [
"$d",
"$p"
]
}
}
}
}
},
"weight": {
"$reduce": {
"input": {
"$filter": {
"input": {
"$map": {
"input": "$weight",
"as": "w",
"in": {
"$cond": [
{
"$ne": [
"$w.weight",
null
]
},
{
"$let": {
"vars": {
"o": [
[
"$w.weight",
"$w.sum"
]
]
},
"in": {
"$arrayToObject": "$o"
}
}
},
null
]
}
}
},
"as": "f",
"cond": {
"$ne": [
"$f",
null
]
}
}
},
"initialValue": {},
"in": {
"$let": {
"vars": {
"d": "$value",
"p": "$this"
},
"in": {
"$mergeObjects": [
"$d",
"$p"
]
}
}
}
}
}
}
},
{
"$project": {
"details": "$ROOT"
}
}
])
Здесь я пытаюсь получить flavour
и weight
с их количеством, вручную добавляя эти поля на $filter
этапе. Я хочу сделать это, не принимая на себя эти ключи. Таким образом, даже если в массиве присутствует 20 элементов details
, он сопоставит эти элементы и покажет мне вывод с их количеством соответственно.
Я надеюсь, вы, ребята, понимаете.
Игровая площадка:https://mongoplayground.net/p/j1mzgWvcmvd
Ответ №1:
Я парень с форума Mongodb:
Попробуйте это https://mongoplayground.net/p/tfyfpIkHilQ
Комментарии:
1. Если это вас устраивает, попробуйте прочитать и понять конвейер. Если у вас есть вопросы, просто задавайте 🙂
2. Да, я это понимаю. Я скучаю
count
по группе «В». Отличная работа!! 🙂
Ответ №2:
Вам нужно изменить схему, то, что вы хотите сделать, легко, и оба эти запроса настолько сложны и медленны, что даже второй, который намного меньше, имеет 2 $unwind
и 3 $group
с 3 $arrayToObject
и 8 этапами в общей сложности из-за схемы и схемы ответа.
Не храните данные в ключах документов, это делают люди, которые новички в MongoDB, я тоже это делал, но это все усложняет.(я не могу сказать, как никогда не делай этого, но тебе это здесь не нужно)
Ваша схема должна быть примерно такой
{
"_id": "2",
"title": "Pretzels",
"contain": "salt",
"details": [
{
"type" : "flavour",
"value" : "Wheat"
},
{
"type" : "weight",
"value" : "10KG"
},
{
"type" : "sugar",
"value" : "15KG"
}
]
}
Преобразует вашу схему в новую схему и выдает нужные вам результаты, но без данных в ключах (первая часть вам бы не понадобилась, вам понадобился бы только приведенный ниже запрос, если бы у вас была эта схема с самого начала)
Запрос с новой схемой (без данных в ключах)
[{"$unwind": { "path": "$details"}},
{"$replaceRoot": {"newRoot": "$details"}},
{
"$group": {
"_id": {
"type": "$type",
"value": "$value"
},
"sum": {"$sum": 1}
}
},
{
"$replaceRoot": {
"newRoot": {"$mergeObjects": ["$_id","$ROOT"]}
}
},
{"$project": {"_id": 0}},
{
"$group": {
"_id": "$type",
"values": {
"$push": {
"value": "$value",
"sum": "$sum"
}
}
}
},
{"$addFields": {"type": "$_id"}},
{"$project": {"_id": 0}}
]
Операторы MongoDB не предназначены для поддержки данных в ключах или динамических ключах(ключи uknown) (для этого вы делаете сложные вещи, подобные описанным выше).
Если вы хотите изменить свою схему, либо сделайте это с помощью обновления в базе данных, либо перенесите документы в приложение и сделайте это с помощью javascript, а затем вставьте заново.
Даже если вы решите этот вопрос в следующем, у вас снова возникнут проблемы.