У меня такая схема:
_id
dates :
date :
year
month
day
other unrelated fields
Я уже сгруппировал каждый _id таким образом, чтобы даты содержали несколько объектов даты (которые содержат год, месяц, день). Теперь я хочу сгруппировать каждый объект даты по году и месяцу, чтобы получить количество дат, соответствующих году и месяцу. Например, если у меня есть следующий документ:
_id : 124567789554
dates :
date :
year : 2018
month : 9
day : 1
date :
year : 2018
month : 9
day : 2
date :
year : 2018
month : 9
day : 3
date :
year : 2018
month : 10
day : 1
Результат, который я хочу:
_id : 124567789554
dates :
date :
year : 2018
month : 9
count : 3
date :
year : 2018
month : 10
count : 1
Как я могу это сделать?
Обновлено: для некоторого дополнительного контекста мне сначала нужно сгруппировать по personId. Изначально схема выглядит так:
_Id (automatically generated by mongoDB)
personId
date
Есть несколько строк с одним и тем же personId, соответствующим дате. Мне нужно сначала сгруппировать так, чтобы _Id = personId, и объединить даты вместе. Как я могу делать и то, и другое одновременно? Мой текущий запрос:
{
_id: "$personId",
dates: {
$addToSet: "$date"
},
other unrelated fields
}
Если вы сохраните свое поле в формате BSON Дата, это легко сделать с помощью групповая агрегация.
Очень похожий пример кода из Mongo Document:
db.sales.aggregate(
[
{
$group : {
_id : { month: { $month: "$date" }, day: { $dayOfMonth: "$date" }, year: { $year: "$date" } },
totalPrice: { $sum: { $multiply: [ "$price", "$quantity" ] } },
averageQuantity: { $avg: "$quantity" },
count: { $sum: 1 }
}
}
]
)
Результат:
{ "_id" : { "month" : 3, "day" : 15, "year" : 2014 }, "totalPrice" : 50, "averageQuantity" : 10, "count" : 1 }
{ "_id" : { "month" : 4, "day" : 4, "year" : 2014 }, "totalPrice" : 200, "averageQuantity" : 15, "count" : 2 }
{ "_id" : { "month" : 3, "day" : 1, "year" : 2014 }, "totalPrice" : 40, "averageQuantity" : 1.5, "count" : 2 }
Используйте $group
для группировки по идентификатору человека, месяцу и году и подсчитайте количество совпадений, за которым следует $group
, чтобы собрать все даты с годом и месяцем и подсчитать для каждого идентификатора человека.
db.colname.aggregate([
{"$group":{
"_id":{"personId":"$personId","year":"$date.year","month":"$date.month"},
"count":{"$sum":1}
}},
{"$group":{
"_id":"$_id.personId",
"dates":{"$push":{"year":"$_id.year","month":"$_id.month","count":"$count"}}
}}
])
Это решение работает, спасибо! Как я могу получить доступ к объекту внутри массива дат? Я пытаюсь сопоставить счетчик $, чтобы создать новое логическое поле, которое возвращает истину, если любое из счетчиков за любой месяц больше 5.
Yw. Добавьте "countgt5":{"$cond":[{"$gt":["$count",5]},true,false]}
после поля count в $ push.
Это добавляет поле истина / ложь к КАЖДОМУ счетчику года / месяца, но я хочу, чтобы это поле возвращало истину / ложь, если ЛЮБОЙ год / месяц имеют счет больше 5 (так что только одно из этого поля для каждого документа, вместо одного поля для каждого года / месяца)
ах. Пропустил эту часть. Добавьте следующий этап после $ group stage. {"$addFields":{"countgt5":{"$gt":[{"$size":{"$filter":{"input":"$dates","cond":{"$gt":["$$this.count",5]}}}},0]}}}
Ты бог. Большое спасибо! Я совершенно новичок в запросах NoSQL и определенно многому здесь научился.
Я думаю, что мой немного отличается, потому что сначала мне нужно сгруппировать по personId. Начальная схема выглядит так: _id, personId, date, ... Поскольку одному человеку соответствует несколько дат, существует несколько строк personId с соответствующей датой.