Запрос Mongodb на месяц, день, год... дата и время

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

для даты "17-11-2011 18:00" Я хранил:

date = datetime.datetime(2011, 11, 17, 18, 0)
db.mydatabase.mycollection.insert({"date" : date})

Я хотел бы сделать такой запрос

month = 11
db.mydatabase.mycollection.find({"date.month" : month})

или

day = 17
db.mydatabase.mycollection.find({"date.day" : day})

Кто-нибудь знает, как сделать этот запрос?

Ответ 1

Даты хранятся в формате временных меток. Если вы хотите все, что принадлежит определенному месяцу, запрос для начала и конца месяца.

var start = new Date(2010, 11, 1);
var end = new Date(2010, 11, 30);

db.posts.find({created_on: {$gte: start, $lt: end}});
//taken from http://cookbook.mongodb.org/patterns/date_range/

Ответ 2

Вы не можете напрямую запрашивать коллекции mongodb по компонентам даты, например день или месяц. Но его можно использовать с помощью специального выражения $where javascript

db.mydatabase.mycollection.find({$where : function() { return this.date.getMonth() == 11} })

или просто

db.mydatabase.mycollection.find({$where : 'return this.date.getMonth() == 11'})

(Но я предпочитаю первую)

Проверьте приведенные ниже команды оболочки, чтобы получить части даты

>date = ISODate("2011-09-25T10:12:34Z")
> date.getYear()
111
> date.getMonth()
8
> date.getdate()
25

EDIT:

Используйте $, где только если у вас нет другого выбора. Это связано с проблемами производительности. Пожалуйста, ознакомьтесь с приведенными ниже комментариями @kamaradclimber и @dcrosta. Я открою этот пост, чтобы другие люди узнали об этом.

и посмотрите ссылку $где Классы и функции в запросах для получения дополнительной информации

Ответ 3

как насчет сохранения месяца в собственном свойстве, так как вам нужно запросить его? менее элегантный, чем $where, но, скорее всего, лучше, поскольку он может быть проиндексирован.

Ответ 4

Если вы хотите искать документы, относящиеся к определенному месяцу, обязательно выполните запрос следующим образом:

// Anything greater than this month and less than the next month
db.posts.find({created_on: {$gte: new Date(2015, 6, 1), $lt: new Date(2015, 7, 1)}});

Избегайте как можно большего количества запросов, как показано ниже.

// This may not find document with date as the last date of the month
db.posts.find({created_on: {$gte: new Date(2015, 6, 1), $lt: new Date(2015, 6, 30)}});

// don't do this too
db.posts.find({created_on: {$gte: new Date(2015, 6, 1), $lte: new Date(2015, 6, 30)}});

Ответ 5

Вы можете запустить агрегированную операцию с помощью функции aggregate(), которая принимает $redact, который использует Операторы агрегирования даты в выражении условия:

var month = 11;
db.collection.aggregate([
    {
        "$redact": {
            "$cond": [
                { "$eq": [ { "$month": "$createdAt" }, month ] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

Для другого запроса

var day = 17;
db.collection.aggregate([
    {
        "$redact": {
            "$cond": [
                { "$eq": [ { "$dayOfMonth": "$createdAt" }, day ] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

Использование OR

var month = 11,
    day = 17;
db.collection.aggregate([
    {
        "$redact": {
            "$cond": [
                { 
                    "$or": [ 
                        { "$eq": [ { "$month": "$createdAt" }, month ] },
                        { "$eq": [ { "$dayOfMonth": "$createdAt" }, day ] }
                    ] 
                },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

Использование AND

var month = 11,
    day = 17;
db.collection.aggregate([
    {
        "$redact": {
            "$cond": [
                { 
                    "$and": [ 
                        { "$eq": [ { "$month": "$createdAt" }, month ] },
                        { "$eq": [ { "$dayOfMonth": "$createdAt" }, day ] }
                    ] 
                },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

Оператор $redact включает в себя функциональные возможности $project и $match конвейер и вернет все документы, соответствующие условию, используя $$KEEP и отбросить из конвейера те, которые не, используя переменную $$PRUNE.

Ответ 6

Вы можете найти записи по месяцам, дням, годам и датам с помощью операторов агрегирования даты, например $dayOfYear, $dayOfWeek, $month, $year и т.д.

В качестве примера, если вы хотите, чтобы все заказы, созданные в апреле 2016 года, вы можете использовать ниже.

db.getCollection('orders').aggregate(
   [
     {
       $project:
         {
           doc: "$$ROOT",
           year: { $year: "$created" },
           month: { $month: "$created" },
           day: { $dayOfMonth: "$created" }
         }
     },
     { $match : { "month" : 4, "year": 2016 } }
   ]
)

Здесь создается поле типа даты в документах, а $$ ROOT мы использовали для передачи всего другого поля для последующего проектирования на следующий этап и даем нам всю деталь документов.

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

Ответ 7

Вы можете использовать MongoDB_DataObject оболочку для выполнения такого запроса, как показано ниже:

$model = new MongoDB_DataObject('orders');

$model->whereAdd('MONTH(created) = 4 AND YEAR(created) = 2016');

$model->find();

while ($model->fetch()) {
    var_dump($model);
}

ИЛИ, аналогично, используя прямую строку запроса:

$model = new MongoDB_DataObject();

$model->query('SELECT * FROM orders WHERE MONTH(created) = 4 AND YEAR(created) = 2016');

while ($model->fetch()) {
    var_dump($model);
}