Совокупный вложенный массив в Mongodb

У меня есть коллекция монго, лежат так:

    {
"_id":ObjectId("55f16650e3cf2242a79656d1"),
"user_id":11,
"push":[
ISODate("2015-09-08T11:14:18.285      Z"),
ISODate("2015-09-08T11:14:18.285      Z"),
ISODate("2015-09-09T11:14:18.285      Z"),
ISODate("2015-09-10T11:14:18.285      Z"),
ISODate("2015-09-10T11:14:18.285      Z")
]
}{
"_id":ObjectId("55f15c78e3cf2242a79656c3"),
"user_id":12,
"push":[
ISODate("2015-09-06T11:14:18.285      Z"),
ISODate("2015-09-05T11:14:18.285      Z"),
ISODate("2015-09-07T11:14:18.285      Z"),
ISODate("2015-09-09T11:14:18.285      Z"),
ISODate("2015-09-09T11:14:18.285      Z"),
ISODate("2015-09-10T11:14:18.285      Z"),
ISODate("2015-09-11T11:14:18.285      Z")
]
}

Как я могу найти user_ids где количество timeStamps < 3 и имеющий дату (отметка времени)> (currentDate-5) в одном запросе. Я буду использовать php и не хочу приносить все документы в память.

Объяснение:

user_id : date       : count
11      : 2015-09-08 : 2
2015-09-09 : 1
2015-09-10 : 2

12      : 2015-09-05 : 1
2015-09-06 : 1
2015-09-07 : 1
2015-09-09 : 2
2015-09-10 : 1
2015-09-11 : 1

Если дата установлена ​​на 2015-09-09 (пользовательский ввод), это даст 3 (количество) для user_id 11 и 4 (количество) для user_id 12. Так что предположим, что счетчик равен 3 (пользовательский ввод). Запрос должен вернуть 11 (user_id). Если для счетчика установлено значение 2, то user_id не будет доступен, а если для счетчика установлено значение 5, он должен вернуть как 11, так и 12

2

Решение

Чтобы решить эту проблему, вам нужен конвейер агрегации, который сначала «фильтрует» результаты по «последним 5 дням», а затем по существу «суммирует» количество элементов массива, присутствующих в каждом квалифицирующем документе, чтобы затем определить, меньше ли «итоговое значение», чем три».

$size Здесь действительно помогает оператор агрегации MongoDB, а также $map и некоторая дополнительная фильтрация через $setDifference для false результаты возвращены из $map, как делать это «в документе сначала» и «внутри» $group этап требуется, является наиболее эффективным способом обработки этого

$result = $collection->aggregate(array(
array( '$match' => array(
'push' => array(
'time' => array(
'$gte' =>  MongoDate( strtotime('-5 days',time()) )
)
)
)),
array( '$group' => array(
'_id' => '$user_id',
'count' => array(
'$sum' => array(
'$size' => array(
'$setDifference' => array(
array( '$map' => array(
'input' => '$push',
'as' => 'time',
'in' => array(
'$cond' => array(
array( '$gte' => array(
'$$time',
MongoDate( strtotime('-5 days',time()) )
)),
'$time',
FALSE
)
)
)),
array(FALSE)
)
)
)
)
)),
array( '$match' => array(
'count' => array( '$lt' => 3 )
))
));

Таким образом, после всей работы сначала нужно найти «возможные» документы, которые содержат записи массива, отвечающие критериям, через $match а затем найдите «общий» размер соответствующих элементов массива в $groupпотом финал $match исключает все результаты, которые меньше трех в общем размере.


Для в значительной степени «мозгов JavaScript» (таких как я, хорошо обученных этому) это в основном такой проект:

db.collection.aggregate([
{ "$match": {
"push": {
"$gte": new Date( new Date().valueOf() - ( 5 * 1000 * 60 * 60 * 24 ))
}
}},
{ "$group": {
"_id": "$user_id",
"count": {
"$sum": {
"$size": {
"$setDifference": [
{ "$map": {
"input": "$push",
"as": "time",
"in": {
"$cond": [
{ "$gte": [
"$$time",
new Date(
new Date().valueOf() -
( 5 * 1000 * 60 * 60 * 24 )
)
]},
"$$time",
false
]
}
}},
[false]
]
}
}
}
}},
{ "$match": { "count": { "$lt": 3 } } }
])

Кроме того, будущие версии MongoDB будут предлагать $filter, что упрощает весь $map а также $setDifference часть заявления:

db.collection.aggregate([
{ "$match": {
"push": {
"$gte": new Date( new Date().valueOf() - ( 5 * 1000 * 60 * 60 * 24 ))
}
}},
{ "$group": {
"_id": "$user_id",
"count": {
"$sum": {
"$size": {
"$filter": {
"input": "$push",
"as": "time",
"cond": {
"$gte": [
"$$time",
new Date(
new Date().valueOf() -
( 5 * 1000 * 60 * 60 * 24 )
)
]
}
}
}
}
}
}},
{ "$match": { "count": { "$lt": 3 } } }
])

Также следует отметить, что «даты», вероятно, лучше всего рассчитывать «до» определения конвейера как отдельной переменной для лучшей точности.

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector