2014-12-15 2 views
1

Это мой документ структура:MongoDB агрегат

{ 
"_id":ObjectId("548eb9fe8ad582f2f9976973"), 
"RECNUM":"1008", 
"ART_NR":"1014", 
"ART_NRA":"10010700", 
"ART_BEZ":{ }, 
"BES1":{ }, 
"markings":[ ], 
"prices":[ 
    { 
    "DATUM_VON":"2011-04-01", 
    "DATUM_BIS":"", 
    "MENG_BETR_BIS":"1.0000", 
    "PROZ_BETR":"4.2000" 
    }, 
    { 
    "DATUM_VON":"2011-04-01", 
    "DATUM_BIS":"", 
    "MENG_BETR_BIS":"250.0000", 
    "PROZ_BETR":"3.5000" 
    }, 
    { 
    "DATUM_VON":"2011-04-01", 
    "DATUM_BIS":"", 
    "MENG_BETR_BIS":"500.0000", 
    "PROZ_BETR":"3.4000" 
    }, 
    { 
    "DATUM_VON":"2011-04-01", 
    "DATUM_BIS":"", 
    "MENG_BETR_BIS":"1000.0000", 
    "PROZ_BETR":"3.3000" 
    }, 
    { 
    "DATUM_VON":"2011-04-01", 
    "DATUM_BIS":"", 
    "MENG_BETR_BIS":"2500.0000", 
    "PROZ_BETR":"3.2000" 
    }, 

    { 
    "DATUM_VON":"2012-09-01", 
    "DATUM_BIS":"", 
    "MENG_BETR_BIS":"1.0000", 
    "PROZ_BETR":"5.4000" 
    }, 
    { 
    "DATUM_VON":"2012-09-01", 
    "DATUM_BIS":"", 
    "MENG_BETR_BIS":"250.0000", 
    "PROZ_BETR":"4.5000" 
    }, 
    { 
    "DATUM_VON":"2012-09-01", 
    "DATUM_BIS":"", 
    "MENG_BETR_BIS":"500.0000", 
    "PROZ_BETR":"4.3500" 
    }, 
    { 
    "DATUM_VON":"2012-09-01", 
    "DATUM_BIS":"", 
    "MENG_BETR_BIS":"1000.0000", 
    "PROZ_BETR":"4.2000" 
    }, 
    { 
    "DATUM_VON":"2012-09-01", 
    "DATUM_BIS":"", 
    "MENG_BETR_BIS":"2500.0000", 
    "PROZ_BETR":"4.1000" 
    } 

] }

Мне нужно извлечь в массиве цен на документы, которые содержат максимальное значение даты. Таким образом, в этом случае все документы (4), которые имеют значение 2012-09-01 в качестве значения.

Я попытался это:

db.products.aggregate([ 
    { $match: {RECNUM: '1008'}}, 
    {"$unwind": "$prices"}, 
    {$match: { "$max": "$prices.DATUM_VON"}} 
]); 

Но это выдает ошибку, как я предполагаю, что я не могу использовать оператор $ макс в $ матче. Как я могу это достичь?

+0

Будьте осторожны с типами. Все данные в вашем примере хранятся в виде строк, которые могут привести к тому, что некоторые операции будут работать не так, как ожидалось. Вы должны использовать объекты ISODate() для дат, если это вообще возможно. – Martin

+0

@Martin Я согласен с общим настроем, но комментарий действительно не подходит для решения проблемы или требует уточнения, как должно быть. –

ответ

4

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

Вы действительно хотите нечто более сложное, чем ваша первоначальная попытка. Дело в том, что вам нужно найти максимальное значение в массиве для этого поля, а затем вам нужно отфильтровать содержимое массива для этого значения. Так что в основном это:

db.collection.aggregate([ 
    { "$match": { 
     "RECNUM": "1008" 
    }}, 
    { "$unwind": "$prices" }, 
    { "$group": { 
     "_id": "$_id", 
     "RECUM": { "$first": "$RECNUM" }, 
     "prices": { "$push": "$prices" }, 
     "max_date": { 
      "$max":"$prices.DATUM_VON" 
     } 
    }}, 
    { "$unwind": "$prices" }, 
    { "$project": { 
     "RECNUM": 1, 
     "prices": 1, 
     "matched": { 
      "$eq": [ "$max_date", "$prices.DATUM_VON" ] 
     } 
    }}, 
    { "$match": { "matched": true } }, 
    { "$group": { 
     "_id": "$_id", 
     "RECNUM": { "$first": "$RECNUM" }, 
     "prices": { "$push": "$prices" } 
    }} 
]) 

Мы можем получить немного больше фантазии от версии MongoDB 2.6 и вверх до тех пор, как элементы массива являются уникальными:

db.collection.aggregate([ 
    { "$match": { 
     "RECNUM": "1008" 
    }}, 
    { "$unwind": "$prices" }, 
    { "$group": { 
     "_id": "$_id", 
     "RECUM": { "$first": "$RECNUM" }, 
     "prices": { "$push": "$prices" }, 
     "max_date": { 
      "$max":"$prices.DATUM_VON" 
     } 
    }}, 
    { "$project": { 
     "RECNUM": 1, 
     "prices": { 
      "$setDifference": [ 
       "$map": { 
        "input": "$prices", 
        "as": "p", 
        "in": { 
         "$cond": [ 
          { "$eq": [ "$$p.DATNUM_VON", "$max_date" ] }, 
          "$$p", 
          false 
         ] 
        } 
       }, 
       false 
      ] 
     } 
    }} 
]) 

Выглядит немного пожирнее, но из MongoDB 2.6 и В большей степени это, как правило, более быстрый способ сделать это, и особенно с большими массивами.

Это все в аббревиатуре обозначений для полей, которые могут потребоваться для вашего фактического вывода, но вы должны получить общую идею. Оператор $first вы друг, когда группируете определенные значения.

+0

ничего себе! Спасибо, спасибо. Я использовал первое предложение, поскольку оно кажется более интуитивным для меня. Я буду анализировать это, чтобы понять каждую часть. – d3rick

+0

@ d3rick Во что бы то ни стало. Но не дисконтируйте второй листинг. Если у вас есть много документов, которые соответствуют исходным условиям, и в этих документах есть большие массивы, вторая форма (хотя выглядит более сложной) намного быстрее, чем первая. Оператор '$ map' немного привыкает, но, как правило, более эффективная форма. –

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