Запрашивает диапазон дат за последние 30 дней с помощью Mongoid и Ruby?

#ruby #mongodb #mongoid #date #range

#ruby #mongodb #mongoid #Дата #диапазон

Вопрос:

Как мне запросить диапазон дат (скажем, за последние 30 дней) с помощью Mongoid и Ruby?

Мне нужно получить массив или хэш, подобный следующему:

 {
    15 => 300,
    14 => 23,
    13 => 23
    ...
    30 => 20  # Goes over into previous month
    28 => 2
}
  

В настоящее время я сохраняю каждый документ с экземпляром DateTime, а также с целочисленным полем метки времени unix.

Ключи в приведенном выше хэше — это дни, а значения — сумма всех продаж за эти дни.

Есть идеи?

Ответ №1:

Есть более простой способ:

 Sale.where(created_at: (30.days.ago..Time.now))
  

Отрегулируйте временной диапазон в соответствии с требованиями.

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

1. Для этого требуется ActiveSupport для части .days.ago

2. Я не думаю, что вы можете добавить несколько параметров с помощью синтаксиса хэша таким образом. Хотя это может быть неправильно.

3. @AshBlue — это один аргумент типа Range. ruby-doc.org/core-2.0.0/Range.html

4. Range в ruby это очень дорого . Несмотря на хороший синтаксис, я бы выбрал выполнение gte и lte

5. @oma — не могли бы вы дать некоторую информацию / ссылку, почему диапазоны ruby являются дорогостоящими, особенно в этом контексте (запрос mongodb)?

Ответ №2:

Вот как сделать все это в rubyland:

 sales_by_date = Hash.new(0)

Sale.where(:created_at.gte => (Date.today - 30)).order_by(:created_at, :desc).each do |s|
  sales_by_date[s.created_at.strftime("%m-%d")]  = 1
end
  

Это создаст хэш с ключами «месяц-день», причина в том, что в некоторых месяцах меньше 30 дней, и это приведет к столкновению ключей, если запрос всегда равен 30.

Если вам нужен другой диапазон, измените запрос:

 # Between 10 and 20 days ago
start_day       = 10
end_day         = 20

Sale.where(:created_at.gte => (Date.today - end_day), :created_at.lte => (Date.today - start_day))
  

Измените created_at на любое имя вашего поля даты и времени.

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

1. Если использовать 2012-06-16 вместо (Date.today - 30) , то как написать запрос?

2. @harsh4u: сначала преобразуйте строку в объект даты. Date.parse("2012-06-16")

3. это далеко не идеальное решение, приведенные ниже ответы намного лучше.

4. Sale.where(:end_date.gte => (Дата.сегодня), :begin_date.lte => (Дата.сегодня)).order(begin_date: :desc)

Ответ №3:

Вы также можете написать запрос, используя between метод, подобный:

 Sale.between(created_at: (30.days.ago..Time.now))
  

Ответ №4:

Что, если вы забыли указать временные метки в своей модели? 🙁

Нет проблем! Просто используйте временную метку в BSON: ObjectId

Получить продажи за последние 30 дней.

 Sale.where(:id.gte => Moped::BSON::ObjectId.from_time((Date.today - 30).to_time))
  

Поскольку id поле является индексом, это вполне может быть самым быстрым запросом.

Нужен диапазон дат? Торт.

Получите продажи за последний месяц.

 Sale.and(
  {:id.gte => Moped::BSON::ObjectId.from_time((Date.today.prev_month.beginning_of_month).to_time)},
  {:id.lte => Moped::BSON::ObjectId.from_time((Date.today.prev_month.end_of_month).to_time)}
)
  

Конечно, в этом примере предполагается, что помощники даты Rails…

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

1. Я думаю, что это более лучший ответ. Это сложнее, но у него хорошая производительность. Спасибо!

Ответ №5:

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

Попробуйте что-то вроде этого:

 map = "function () { emit( {this.date.getDate(), {}} )}"
reduce = "function (key, values) { return {date: key, count: values.length } }"

collection.map_reduce(map, reduce, {query: {"date": {"$gt": 30.days.ago } } })
  

Это может сработать.