Запрос диапазона дат Mongoid

#ruby-on-rails #mongodb #mongoid

#ruby-on-rails #mongodb #mongoid

Вопрос:

Кажется, я не могу найти ничего, что могло бы сделать запрос диапазона дат с использованием Mongoid / Rails. Ниже приведены некоторые запросы, которые я пробовал (среди примерно 100 других). Если он возвращает что-либо, он всегда игнорирует ‘end_date’. Обе даты являются datetimes…

 all(:conditions => {:created_at => start_date.to_datetime..end_date.to_datetime})
  

результаты в:

 NoMethodError: undefined method `to_i' for Tue, 26 Apr 2011 00:00:00  0000..Fri, 06 May 2011 00:00:00  0000:Range
  

другой пример…

 where(:created_at => {'$gte' => start_date,'$lt' => end_date})
  

запрос выполняется успешно, но конечная дата игнорируется. Результаты возвращаются корректно после даты начала, но не ограничены датой окончания.

Я работал над этой проблемой в течение нескольких дней безрезультатно. Не так много помощи онлайн, на форумах или IRC.

Хотелось бы выяснить, что я делаю не так 🙂

Ответ №1:

В Mongoid обнаружена ошибка. Исправлено.

Для получения дополнительной информации:

https://github.com/mongoid/mongoid/issues/761

https://github.com/mongoid/mongoid/commit/f326de5acc969e1342e640dc026de7e94bf4cf49#lib/mongoid/matchers.rb

Комментарии:

1. Действительно, это было исправлено в Mongoid 2.0.2, но я нигде не смог найти никакой документации по исправлению этой ошибки … это немного беспокоит, такие ошибки могут оказать серьезное влияние на мои приложения… не уверен, что делать, чтобы предотвратить подобные проблемы, если он снова сломается в будущей версии: (

2. И, похоже, он снова сломался. Mongoid 3.0 здесь, та же проблема.

Ответ №2:

Я провел небольшое исследование и наткнулся на сообщение Advanced Queries, в котором один пользователь спрашивает:

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

Ответ другого пользователя на это:

Используйте собственный тип даты BSON. Внутренне это 64-разрядное целое число, равное количеству миллисекунд, прошедших с эпохи.

Таким образом, вы можете захотеть подойти к этому по-другому и преобразовать количество миллисекунд, прошедших с эпохи, для ваших запросов диапазона. Таким образом, вы выполняете простой gte/lt для целых чисел. Предложение пользователя относительно новое (опубликовано 3 месяца назад), поэтому оно все еще может быть наиболее надежным способом сравнения дат с Mongo в целом (и, следовательно, с Mongoid).

Ответ №3:

Я использовал оболочку MongoDB для тестирования этого:

Выполнял это несколько раз

db.con.save({создано: новая дата()})

Затем я получил

 > db.con.find()
{ "_id" : ObjectId("4dc3d380724a42d80d636b09"), "created" : ISODate("2011-05-06T10:54:56.809Z") }
{ "_id" : ObjectId("4dc3d383724a42d80d636b0a"), "created" : ISODate("2011-05-06T10:54:59.699Z") }
{ "_id" : ObjectId("4dc3d385724a42d80d636b0b"), "created" : ISODate("2011-05-06T10:55:01.543Z") }
{ "_id" : ObjectId("4dc3d38b724a42d80d636b0c"), "created" : ISODate("2011-05-06T10:55:07.043Z") }
{ "_id" : ObjectId("4dc3d38c724a42d80d636b0d"), "created" : ISODate("2011-05-06T10:55:08.168Z") }
{ "_id" : ObjectId("4dc3d49d4087861731076f8a"), "created" : ISODate("2011-05-06T10:59:41.755Z") }
  

В качестве даты разделения я выбираю ISODate("2011-05-06T10:55:00Z") создать это с d = new Date(2011,04,06,12,55,00) различиями, поскольку месяц начинается с нуля, а время соответствует часовому поясу utc.
Теперь db.con.find({"created": {$gt:d}}) выдает

 { "_id" : ObjectId("4dc3d385724a42d80d636b0b"), "created" : ISODate("2011-05-06T10:55:01.543Z") }
{ "_id" : ObjectId("4dc3d38b724a42d80d636b0c"), "created" : ISODate("2011-05-06T10:55:07.043Z") }
{ "_id" : ObjectId("4dc3d38c724a42d80d636b0d"), "created" : ISODate("2011-05-06T10:55:08.168Z") }
{ "_id" : ObjectId("4dc3d49d4087861731076f8a"), "created" : ISODate("2011-05-06T10:59:41.755Z") }
  

Итак, MongoDB делает все правильно. Как это сделать в Ruby — это то, чего я не знаю.