Агрегирование данных в ReactiveMongo по дате
Я пытаюсь получить агрегат в ReactiveMongo 0.12 и Play Framework 2.6 (используя коллекции JSON, а не BSON) путем фильтрации дат из коллекции, называемой "посетители". Типичный документ может выглядеть так:
{ "_id": ObjectID("59c33152ca2abb344c575152"), "placeId": ObjectID("59c33152ca2abb344c575152"), "date": ISODate("2017-03-26T00:00:00Z"), "visitors": 1200 }
Итак, отсюда я хочу объединить эти данные, чтобы получить различные итоговые данные о посетителях, средние значения и т. Д., Сгруппировать по placeId (который идентифицирует место в другой коллекции) и отфильтровать по датам после 15-05-2016.
Я основал это на этом подобном вопросе - без совпадения это работает, но без этого - это не так. Там нет ошибки, но она просто не работает:
def getVisitorAggregate(col: JSONCollection) = {
import col.BatchCommands.AggregationFramework.{Group, Match, SumField, AvgField, MinField, MaxField}
val format = new java.text.SimpleDateFormat("dd-MM-YYYY")
val myDate = "15-05-2016"
val parseDate: Date = format.parse(myDate)
val longDate: Long = parseDate.getTime
col.aggregate(
Group(JsString("$placeId"))(
"totalVisitors" -> SumField("visitors"),
"avgVisitors" -> AvgField("visitors"),
"minVisitors" -> MinField("visitors"),
"maxVisitors" -> MaxField("visitors")
),
List(Match(Json.obj("date" -> Json.obj("$gte" -> JsNumber(longDate)))))
)
.map(_.head[VisitorAggregate])
}
Я много часов искал и проверял в Интернете, и не могу найти правильный синтаксис, но это будет просто для тех, кто знает, что я уверен. Спасибо
2 ответа
Я не хочу отвечать на свой вопрос здесь, но теперь, когда я понял это, я действительно хочу разъяснить другим, как это делается с помощью Aggregate. В конечном итоге на этот вопрос было две части.
1) каков синтаксис запроса даты?
Как упомянул @AndriyKuba, и я видел в документации еще не полностью понял; запрос формулируется так:
Json.obj("date" -> Json.obj("$gte" -> Json.obj("$date" -> JsNumber(longDate))))
2) как мне сопоставить запрос в совокупности?
Это больше вопрос порядка запроса. Первоначально я пытался использовать сопоставление после группировки и агрегирования данных - что (очевидно) будет только после фильтрации данных. Поскольку я хотел сначала получить диапазон дат, а затем агрегировать эти данные, которые я должен был сопоставить первым - это также означало, что часть синтаксиса должна была соответственно измениться:
def getVisitorAggregate(col: JSONCollection) = {
import col.BatchCommands.AggregationFramework.{Group, Match, SumField, AvgField, MinField, MaxField}
val format = new java.text.SimpleDateFormat("dd-MM-YYYY")
val myDate = "15-05-2016"
val parseDate: Date = format.parse(myDate)
val longDate: Long = parseDate.getTime
col.aggregate(
Match(Json.obj("date" -> Json.obj("$gte" -> Json.obj("$date" -> JsNumber(longDate))))),
List(Group(JsString("$rstId"))(
"totalVisitors" -> SumField("visitors"),
"avgVisitors" -> AvgField("visitors"),
"minVisitors" -> MinField("visitors"),
"maxVisitors" -> MaxField("visitors")
))
)
.map(_.head[VisitorAggregate])
}
Действительно разочаровывает, что больше нет документации об использовании Play Framework с ReactiveMongo, так как есть много примеров попыток понять синтаксис и логику.
ISODate
это тип Mongodb, и Model.aggregate
не приводит аргументы, поэтому "date" -> Json.obj("$gte" -> JsNumber(longDate))
неправильно.
Вам нужно использовать тип, который будет преобразован в ISODate
Я уверен, что это не так JsNumber
,
Это BSONDateTime
тип вы бы использовали BSON
, но вы этого не сделаете.
Согласно документации это должно быть
JsObject
с$date
JsNumber
поле с отметкой времени (миллисекунды) в качестве значения
Так что решение может быть (я не проверял):
Match(Json.obj("date" -> Json.obj("$gte" -> Json.obj("$date" -> JsNumber(longDate)))))