Найдите записи, которые имеют определенное значение в столбце массива

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

Я хочу найти в этом массиве один конкретный ингредиент.

Я нашел метод include?, который отлично работает в таких случаях, как:

Recipe.find(35).ingredient.include? params[:ingredient]

Я пытаюсь заставить это работать с методом where, чтобы получить что-то вроде этого:

Recipe.where('ingredient.include?', params[:ingredient].to_i)

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

Я не могу понять, как это работает.


person Marine Be    schedule 12.10.2016    source источник
comment
блин, мой insta-dup-hammer не работал, потому что он не был помечен как рубин на рельсах :(   -  person Sergio Tulentsev    schedule 12.10.2016


Ответы (2)


Просто предупреждаем, что сохранение столбца с массивом идентификаторов, как правило, не лучшее решение!

Предпочтительным подходом является ассоциация компании Rail has_and_belongs_to_many. , который использует таблицу соединений (ala ingredients_recipes) для хранения отношения.

Хранение идентификаторов в массиве не является первым делом во многих базах данных, так как оно просто не поддерживается. В Postgres возможно использование оператора @> contains, но вы теряете преимущества реляционной целостности (ограничения внешнего ключа), а также жертвуете автоматическим управлением Rails и другими ORM.

Однако это открытый архитектурный вопрос; если вы имеете дело с данными большого объема (миллионы строк), массивы потенциально могут иметь преимущество в производительности (см. Использование массивов postgres в отношениях). Однако обычно не стоит отказываться от автоматического управления ассоциацией Rails!

person gmcnaughton    schedule 12.10.2016
comment
это не строковый столбец. - person Sergio Tulentsev; 12.10.2016
comment
Правильно, я не заметил тега postgresql. Спасибо! - person gmcnaughton; 12.10.2016
comment
Спасибо! Итак, @gmcnaughton, нормально ли иметь столбец с массивом целых чисел, или вы все еще думаете, что мне нужна таблица соединений (я колебался между двумя вариантами) - person Marine Be; 12.10.2016
comment
Сначала я сделал ту же ошибку при чтении вопроса - вы все равно можете спасти этот ответ, отредактировав его, так как это в основном хороший ответ и не заслуживает отрицательных оценок. - person max; 12.10.2016
comment
@MarineBe Я бы по-прежнему рекомендовал подход к объединению таблиц над массивами, в основном, чтобы облегчить вашу жизнь! Например, Rails будет понимать и управлять записями таблицы соединений за вас. Но похоже, что это открытый архитектурный вопрос с postgres (см. dba.stackexchange.com/questions/11853/) - person gmcnaughton; 12.10.2016
comment
@gmcnaughton есть так много веских причин, по которым вы можете захотеть сохранить массив идентификаторов. На самом деле их так много, что хорошие ребята, взломавшие Postgres, предоставили нам тип столбца массива. Вы заметите, что в документации для типа столбца массива postgres нигде не сказано, чтобы его не использовали. - person Michael Johnston; 05.12.2017
comment
Опыт stackoverflow у всех будет намного эффективнее, если вы сохраните проповеди для комментариев (как это делаю я!) И сохраните ответы для фактических ответов для актуального вопроса < / b>. - person Michael Johnston; 05.12.2017
comment
@MichaelJohnston благодарит за отзыв! Я согласен с тем, что stackoverflow предназначен для ответов, а не для обучения. wiki.c2.com/?MuAnswer - person gmcnaughton; 06.12.2017

Вы можете запросить массив, используя any:

Recipe.where('WHERE ? = ANY (ingredient)', params[:ingredient])

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

class Recipe
  has_many :recipe_ingredients
  has_many :ingredients, though: :recipe_ingredients
end

class RecipeIngredient
  belongs_to :recipe
  belongs_to :ingredient
end

class Ingredient
  has_many :ingredients
  has_many :ingredients, though: :recipe_ingredients
end

Это позволит вам запрашивать с обоих концов:

Recipe.joins(:ingredients)
      .where(ingredients: { name: ['basil', 'thyme'] } )
Ingredient.joins(:recipes)
      .where(recipes: { main_type: 'dessert' } )

Помимо присоединения данных к таблице recipe_ingredients, таких как количество (что невозможно с has_and_belongs_to_many), это также позволит вам напрямую запрашивать таблицу соединения, что может быть очень полезно.

Почему бы не использовать массив?

Потому что ActiveRecord не построен на использовании массивов для хранения ассоциаций. Вы в основном теряете все преимущества ассоциаций ActiveRecord из-за небольшого повышения производительности или его отсутствия. Вы также не можете использовать ограничения внешнего ключа для обеспечения целостности данных в БД.

person max    schedule 12.10.2016
comment
Чтобы найти значение в массиве в Postgres, вы должны сделать SELECT * FROM recipies WHERE 1 = ANY (ingredient); - postgresql.org /docs/current/static/arrays.html - person max; 12.10.2016
comment
Использование правильной таблицы соединений с составным индексом для столбцов внешнего ключа на самом деле может быть более производительным, чем поиск в массиве. - person max; 12.10.2016
comment
Спасибо за совет @max. Я попытался создать таблицу соединения, но я не мог понять, как отправить данные из моей формы в две таблицы, так как некоторые данные принадлежали таблице рецептов, а некоторые - RecipeIngredient. Вот почему я сдался и пошел с массивом. Любой совет или полезная ссылка по этому поводу? - person Marine Be; 12.10.2016
comment
Мой совет - задать новый вопрос и включить пример того, что вы пытались сделать, и в чем проблема. - person max; 12.10.2016
comment
В противном случае это приведет к бесконечному количеству комментариев. - person max; 12.10.2016
comment
Да сэр ! Сделаю. - person Marine Be; 12.10.2016
comment
вот три причины, по которым вы могли бы использовать массив для хранения идентификаторов: 1.) это идентификаторы из другой базы данных, и нет однозначного сопоставления между частью вашей модели, которая заполняется данными из другой. модель. 2.) Вы разрабатываете mvp и не хотите оплачивать стоимость полностью смоделированных отношений в базе данных до тех пор, пока вы на самом деле не разработаете функции, которые их используют. 3.) Отношения нужны вам только для возможного будущего аудита. Любой, кто говорит никогда не использовать массив, просто не работал с достаточным количеством приложений. - person Michael Johnston; 05.12.2017
comment
Я не говорю никогда. Я говорю, что массивы не являются подходящей заменой для приличного дизайна реляционной базы данных, как в 99% случаев, когда новички пытаются создать с ними множество ассоциаций. - person max; 07.12.2017