find_by с массивом json, выполняющим запрос с IN вместо поиска по всему массиву - PullRequest
0 голосов
/ 06 февраля 2020

У меня есть модель (область) с полем jsonb (координаты):

  create_table "areas" do |t|
    t.jsonb "coordinates"
  end

Теперь, если я вставлю массив:

Area.create(coordinates: [1, 2])

, он работает нормально, но ищет it:

Area.find_by(coordinates: [1, 2])

выполняет запрос SQL с IN, например:

SELECT "areas".* FROM "areas" WHERE "areas"."coordinates" IN ($1, $2) LIMIT $3  [["coordinates", "1"], ["coordinates", "2"], ["LIMIT", 1]]

Я пытался найти [[1, 2]] и [[[1, 2]]], но я всегда получаю IN запрос.

(возможно, это проблема рельсов)

Ответы [ 2 ]

1 голос
/ 06 февраля 2020

Вы должны использовать SQL строки при запросе столбцов типа JSON / Array / Hstore. Например:

Event.where("payload->>'kind' = ?", "user_renamed")

Они не являются "нативной" частью интерфейса запросов, поскольку создание запросов гораздо сложнее, чем для обычного столбца, из-за типизации и различных реализаций. ActiveRecord будет просто создавать запросы для этих типов, как если бы он находился в обычном типе столбца, который он понимает. См. Активная запись и PostgreSQL.

Запрос массива в столбце json может быть выполнен с помощью чего-то вроде:

WHERE coordinates @> ANY (ARRAY [1,2,3]::jsonb[]);

Но - возможно, вам следует просто пересмотрите, если использование столбца JSON является хорошей идеей, так как запросы будут ужасными? Типы JSON / JSONB хороши для определенных специализированных задач, когда данные не могут соответствовать схеме, но не должны заменять правильное реляционное моделирование БД. Ненужный JSONB является антипаттерном.

Также, если это географические координаты, вы представляете эти числа либо в виде целых чисел, либо в виде чисел с плавающей точкой, но нет способа указать тип в JSON, кроме добавления . и синтаксический анализатор определяет, является ли 2.0 плавающей точкой или целым числом.

Если вы настраиваете отдельную таблицу для координат, вы действительно можете использовать и использовать ассоциации ActiveRecord и иметь степень нормализации данных, индексов, ссылочной целостности и т. д. на. О, и я упоминал, что вы на самом деле можете запрашивать ваши данные как здравомыслящий человек?

class Area
  has_many :coordinates
end

# rails g model coordinate area:references lat:decimal lng:decimal
class Cooridinate
  belongs_to :area
end


Area.joins(:coordinates).where(coordinates: { lat: 1, lng: 1 })

Вы также можете использовать расширение PostGIS , которое предоставляет специализированные типы столбцов для координат, многоугольников, и другие виды географического материала.

0 голосов
/ 06 февраля 2020

Это то, что вы ищете?

Area.find_by("coordinates = '[1, 2]'")
...