2015-09-12 2 views
2

Рассмотрим сборник, состоящий из документов, следующего вида:нужно максимальное значение в коллекции MongoDB, и его временная метка

{ 
"_id" : ObjectId("55f3600da9fb6e4f937a50a7"), 
"timestamp" : ISODate("2010-01-01T08:10:00Z"), 
"temperature" : 12.31 
} 
{ 
"_id" : ObjectId("55f3600da9fb6e4f937a50a8"), 
"timestamp" : ISODate("2010-01-01T08:15:00Z"), 
"temperature" : 12.48 
} 
... 

Я хочу найти температуру макс на каждый день года, и в времени. Первая часть достаточно легко с агрегацией трубопроводной:

[{"$group" : {"_id" : {"day": { "$dayOfYear": "$timestamp" }}, 
       "max_temperature": {"$max" : "$temperature"}}}, 
{"$sort" : {"_id.day":1}}] 

Это дает мне хороший набор результаты с максимальной температурой на каждый день:

{u'max_temperature': 20.98, u'_id': {u'day': 1}} 
{u'max_temperature': 24.15, u'_id': {u'day': 2}} 
{u'max_temperature': 22.02, u'_id': {u'day': 3}} 
... 

Но, как я получаю метки времени когда каждый ежедневный максимум произошел? Что-то вроде:

{u'max_temperature': 20.98, u'time_of_max': ISODate("2010-01-01T15:11:12"), u'_id': {u'day': 1}} 
{u'max_temperature': 24.15, u'time_of_max': ISODate("2010-01-02T16:03:42"), u'_id': {u'day': 2}} 
{u'max_temperature': 22.02, u'time_of_max': ISODate("2010-01-03T16:33:59"), u'_id': {u'day': 3}} 
... 

ответ

1

Использование $sort первым и $first оператор вместо $max. Но загвоздка в том, что вам нужно «день» снижение детализации присутствовать первый:

[ 
    { "$project": { 
     "day": { "$dayOfYear": "$timestamp" }, 
     "timestamp": 1, 
     "temperature": 1 
    }}, 
    { "$sort": { "day": 1, "temperature": -1 } }, 
    { "$group": { 
     "_id" : "$day", 
     "max_temperature": { "$first": "$temperature" }, 
     "timestamp": { "$first": "$timestamp" } 
    }}, 
    { "$sort": { "_id":1 } } 
] 

После того, как вы едите, что запланированная стоимость на «день», то вход может быть заказан в день с наибольшим значением «температурой» первым , Затем оператор группировки $first будет выбирать поля из «первого» документа, найденного на границе группировки.

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

Технически, это должно работать:

[ 
    { "$sort": { "temperature": -1, "timestamp": 1 } }, 
    { "$group": { 
     "_id" : { "$dayOfYear": "$timestamp" }, 
     "max_temperature": { "$first": "$temperature" }, 
     "timestamp": { "$first": "$timestamp" } 
    }}, 
    { "$sort": { "_id":1 } } 
] 

Но первоначальный порядок сортировки фактически выровнен с ключом группировки, то это, скорее всего, потеряет в общей эффективности.

+0

Ваше первое предложение определенно работает, и это подход, о котором я не думал. Поиск максимальной температуры для каждого дня с использованием исходного подхода занимает около 0,1 с на моей NUC. Добавление времени суток с использованием вашего подхода занимает около 0,4. Жаль, что нет способа сохранить документ, который удовлетворяет агрегату '$ max'. – TomK

+0

@TomK Все дело в том, что то, что вы запрашиваете, это «несколько значений из сопоставленного документа», что является «противоположностью» того, что «$ max» делает. Оператор '$ max' находит« максимум »из« где угодно »в рамках условия группировки, но вы хотите, чтобы« два свойства »находились на границе« максимальной »группировки, и это означает, что должен существовать' 'sort'. Это не «мой» подход, это «единственный» подход без сохранения отдельных предварительно агрегированных данных. И это последнее, что мы часто делаем по соображениям производительности. –

0

db.temp.aggregate ([{$ Проект: {дата: {$ DayOfYear: "$ временная метка"}, температура: "$ Temperatur е", ISODate: "$ временная метка"}}, {$ group: {_ id: "$ date", maxtemp: {"$ max": "$ temp"}, timestam p: {"$ first": "$ ISODate"}}}, {"$ sort": {_ id : 1}}])

+0

Если я правильно понимаю ваш подход, это возвращает время начала каждого дня, а не время максимальной температуры. – TomK

Смежные вопросы