Доступ к полю JSON таблицы соединений с помощью Active Record - PullRequest
0 голосов
/ 25 сентября 2019

Один магазин has_many Продукты и продукт belongs_to Магазин.В магазине есть колонки opening_hours и closing_hours.В каждом столбце хранится хэш, который выглядит следующим образом:

opening_hours = {'Monday' => '12:00', 'Tuesday' => '13:00'}

и т. Д.

Я работаю с текущей датой и временем, и Я хочу получить все продукты, которыеВ магазинах opening_hours меньше текущего времени, что меньше closing_hours. В основном все товары, которые доступны, когда магазин открыт.

Я сделал что-то подобное в своем контроллере:

day_today = Date.today.strftime('%A')
time_now = Time.new.strftime('%H:%M')
@products = Product.joins(shop: [{opening_hours[day_today] < time_now, 
                                 {closing_hours[day_today] > time_now }])

Редактировать

Этот код хранит время открытия в БД

hours_table = shop.search('table')
    opening_hours = {}
    closing_hours = {}
    hours_table.first.search('tr').each do |tr|
      cells = tr.search('td')
      day = cells.first.text.strip
      hours = cells.last.text.strip.tr('-', '').split
      opening_hours[day] = hours[0].to_time.strftime('%H:%M')
      closing_hours[day] = hours[1].to_time.strftime('%H:%M')
    end

shop = Shop.new(
        name: shop_name,
        opening_hours: opening_hours,
        closing_hours: closing_hours
      )
      shop.save

      new_product = Product.new(
        name: foo,
        description: foo,
        price: foo,
        company: 'foo',
      )
      new_product.shop = shop
      new_product.save

Это миграция для добавления часов работы кМагазин.То же самое делается для закрытия часов.

class AddOpeningHoursToShop < ActiveRecord::Migration[5.1]
  def change
    add_column :shops, :opening_hours, :json, default: {}
  end
end

Это миграция для добавления идентификатора магазина к продуктам

class AddShopToProducts < ActiveRecord::Migration[5.1]
  def change
    add_reference :products, :shop, foreign_key: true
  end
end

Есть предположения?

1 Ответ

1 голос
/ 25 сентября 2019

Вы можете использовать оператор ->> для доступа к определенному полю JSON в виде текста:

SELECT opening_hours->>'Monday' AS monday_opening_hour FROM shops;

То же самое для closing_hours, он просто меняет имя столбца и поля.

Таким образом, представление AR в вашем случае будет выглядеть следующим образом:

Product
  .joins(:shop)
  .where(
    "shops.opening_hours->>:day <= :now AND shops.closing_hours->>:day >= :now",
    day: day_today,
    now: time_now
  )

Вы можете легко связать имя ключа и время, которое вы собираетесь запрашивать, здесь как day и now.

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


Это также можно сделать с помощью оператора BETWEEN:

Product
  .joins(:shop)
  .where(
    ":now BETWEEN shops.opening_hours->>:day AND shops.closing_hours->>:day",
    day: day_today,
    now: time_now
  )

Вы можете использовать тот, который вы считаете более понятным.

В любом случае вы можете избавиться от сохранения переменной time_now, используя функцию NOWPostgreSQL.Он будет обрабатывать разницу формата времени, если вы приведете его к тексту (NOW()::text):

Product
  .joins(:shop)
  .where(
    "NOW()::text BETWEEN shops.opening_hours->>:day AND shops.closing_hours->>:day",
    day: day_today
  )

Аналогично, день также можно получить из NOW.Вы можете использовать to_char(NOW(), 'Day') для этого

SELECT to_char(date, 'Day') AS day
FROM generate_series (NOW() - '6 days'::interval, NOW(), '1 day') date;

    day
-----------
 Thursday
 Friday
 Saturday
 Sunday
 Monday
 Tuesday
 Wednesday

Итак:

Product
  .joins(:shop)
  .where("NOW()::text BETWEEN shops.opening_hours->>(to_char(NOW(), 'Day'))
                          AND shops.closing_hours->>(to_char(NOW(), 'Day'))")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...