Несколько вложенных групп в массиве
У меня есть группа элементов в MongoDB, как указано ниже:
/* 1 */
{
"_id" : ObjectId("58736c7f7d43c305461cdb9b"),
"Name" : "Kevin",
"pb_event" : [
{
"event_type" : "Birthday",
"event_date" : "2014-08-31"
},
{
"event_type" : "Anniversary",
"event_date" : "2014-08-31"
}
]
}
/* 2 */
{
"_id" : ObjectId("58736cfc7d43c305461cdba8"),
"Name" : "Peter",
"pb_event" : [
{
"event_type" : "Birthday",
"event_date" : "2014-08-31"
},
{
"event_type" : "Anniversary",
"event_date" : "2015-03-24"
}
]
}
/* 3 */
{
"_id" : ObjectId("58736cfc7d43c305461cdba9"),
"Name" : "Pole",
"pb_event" : [
{
"event_type" : "Birthday",
"event_date" : "2015-03-24"
},
{
"event_type" : "Work Anniversary",
"event_date" : "2015-03-24"
}
]
}
Теперь я хочу получить результат с группой event_date
затем после группы на event_type
, event_type
содержат все имена связанных пользователей, затем количество записей в соответствующем массиве.
Ожидаемый результат
/* 1 */
{
"event_date" : "2014-08-31",
"data" : [
{
"event_type" : "Birthday",
"details" : [
{
"_id" : ObjectId("58736c7f7d43c305461cdb9b"),
"name" : "Kevin"
},
{
"_id" : ObjectId("58736cfc7d43c305461cdba8"),
"name" : "Peter"
}
],
"count" : 2
},
{
"event_type" : "Anniversary",
"details" : [
{
"_id" : ObjectId("58736c7f7d43c305461cdb9b"),
"name" : "Kevin"
}
],
"count" : 1
}
]
}
/* 2 */
{
"event_date" : "2015-03-24",
"data" : [
{
"event_type" : "Anniversary",
"details" : [
{
"_id" : ObjectId("58736cfc7d43c305461cdba8"),
"name" : "Peter"
}
],
"count" : 1
},
{
"event_type" : "Birthday",
"details" : [
{
"_id" : ObjectId("58736cfc7d43c305461cdba9"),
"name" : "Pole"
}
],
"count" : 1
},
{
"event_type" : "Work Anniversary",
"details" : [
{
"_id" : ObjectId("58736cfc7d43c305461cdba9"),
"name" : "Pole"
}
],
"count" : 1
}
]
}
1 ответ
При использовании структуры агрегации вам потребуется запустить конвейер, который имеет следующие этапы, чтобы получить желаемый результат:
db.collection.aggregate([
{ "$unwind": "$pb_event" },
{
"$group": {
"_id": {
"event_date": "$pb_event.event_date",
"event_type": "$pb_event.event_type"
},
"details": {
"$push": {
"_id": "$_id",
"name": "$Name"
}
},
"count": { "$sum": 1 }
}
},
{
"$group": {
"_id": "$_id.event_date",
"data": {
"$push": {
"event_type": "$_id.event_type",
"details": "$details",
"count": "$count"
}
}
}
},
{
"$project": {
"_id": 0,
"event_date": "$_id",
"data": 1
}
}
])
В приведенном выше конвейере первым шагом является $unwind
оператор
{ "$unwind": "$pb_event" }
что очень удобно, когда данные хранятся в виде массива. Когда оператор разматывания применяется к полю данных списка, он создает новую запись для каждого элемента поля данных списка, к которому применяется размотка. Это в основном сглаживает данные.
Это необходимая операция для следующего этапа конвейера, $group
шаг, на котором вы группируете сплющенные документы по деконструированным pb_event
поля массива event_date
а также event_type
:
{
"$group": {
"_id": {
"event_date": "$pb_event.event_date",
"event_type": "$pb_event.event_type"
},
"details": {
"$push": {
"_id": "$_id",
"name": "$Name"
}
},
"count": { "$sum": 1 }
}
},
$group
Оператор конвейера похож на SQL GROUP BY
пункт. В SQL вы не можете использовать GROUP BY
если вы не используете какую-либо функцию агрегирования. Точно так же вы должны использовать функцию агрегирования в MongoDB (называемую оператором накопителя). Вы можете прочитать больше о функциях агрегирования здесь.
В этом $group
операция, логика для расчета совокупного количества, т. е. общее количество документов в группе, используя $sum
оператор аккумулятора. В пределах одного и того же конвейера вы можете агрегировать список name
а также _id
субдокументы с использованием $push
оператор, который возвращает массив значений выражений для каждой группы.
Предыдущий $group
трубопровод
{
"$group": {
"_id": "$_id.event_date",
"data": {
"$push": {
"event_type": "$_id.event_type",
"details": "$details",
"count": "$count"
}
}
}
}
будет дополнительно агрегировать результаты последнего конвейера, группируя по event_date
, которая формирует основу для желаемого вывода путем создания нового списка данных с использованием $push
а потом финал $project
этап трубопровода
{
"$project": {
"_id": 0,
"event_date": "$_id",
"data": 1
}
}
изменяет поля документов путем переименования _id
поле для event_date
и сохраняя другое поле.