Поиск документов, действительных на определенную дату

У меня есть некоторые данные, хранящиеся в коллекции mongodb, похожие на:

{"_id": 1, "category": "food", "name": "chips", "price": 1.50, "effectiveDate": ISODate("2013-03-01T07:00:00Z")} 
{"_id": 2, "category": "food", "name": "chips", "price": 1.75, "effectiveDate": ISODate("2013-03-05T07:00:00Z")}
{"_id": 3, "category": "food", "name": "chips", "price": 1.90, "effectiveDate": ISODate("2013-03-10T07:00:00Z")}
{"_id": 4, "category": "beverage", "name": "pop", "price": 2.00, "effectiveDate": ISODate("2013-03-01T07:00:00Z")}
{"_id": 5, "category": "beverage", "name": "pop", "price": 2.25, "effectiveDate": ISODate("2013-03-05T07:00:00Z")}
{"_id": 6, "category": "beverage", "name": "pop", "price": 1.80, "effectiveDate": ISODate("2013-03-10T07:00:00Z")}

Как в mongodb мне написать запрос, который вернет документы, которые были активны в определенную дату, сгруппированные по категориям?

Если бы я указал 6 марта 2013 года, я бы ожидал увидеть результаты:

{"_id": 2, "category": "food", "name": "chips", "price": 1.75, "effectiveDate": ISODate("2013-03-05T07:00:00Z")}
{"_id": 5, "category": "beverage", "name": "pop", "price": 2.25, "effectiveDate": ISODate("2013-03-05T07:00:00Z")}

Я новичок в монго и пытался сделать это, используя группу, агрегат и карту, но просто крутился кругами.


person ReKo    schedule 08.03.2013    source источник
comment
что вы хотите сделать с другими полями, такими как цена? самая высокая цена? самая низкая цена?   -  person Jonathan Ong    schedule 08.03.2013
comment
Мне не нужны никакие расчеты. Я просто ищу документы, применимые в конкретный момент времени.   -  person ReKo    schedule 08.03.2013


Ответы (1)


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

Мой запрос:

db.yourcollection.aggregate([

    /* First exclude everything that is superior to a given date */
    {$match:{effectiveDate:{$lte:new Date(2013,2,6)}}},

    /* Sort the rest by date, descending */
    {$sort:{effectiveDate:-1}},

    /* Group by name+category and grab only the first result
       (the newest below that date) */
    {$group:{_id:{name:'$name',category:'$category'}, effectiveDate:{$first:"$effectiveDate"},price:{$first:"$price"}}},

    /* You said you want the results grouped by category.
       This last $group does that and returns all matching products inside an array
       It also removes the duplicates */
    {$group:{_id:'$_id.category',products:{$addToSet:{name:"$_id.name",price:"$price",effectiveDate:"$effectiveDate"}}}}

])

Вывод такой:

{
    "result": [
        {
            "_id": "food",
            "products": [
                {
                    "name" : "chips",
                    "price" : 1.75,
                    "effectiveDate" : ISODate("2013-03-05T07:00:00Z")
                }
            ]
        },
        {
            "_id" : "beverage",
            "products": [
                {
                    "name" : "pop",
                    "price" : 2.25,
                    "effectiveDate" : ISODate("2013-03-05T07:00:00Z")
                }
            ]
        }
    ],
    "ok":1
}

Вы можете изменить окончательный вывод, изменив последний $group или используя $project

person Victor Schröder    schedule 15.03.2013
comment
Спасибо, что нашли время, чтобы решить эту проблему. Я реализую ваши выводы и сообщу, сработало ли это для меня. - person ReKo; 20.03.2013