Поиск сериализованных данных с использованием активной записи - PullRequest
46 голосов
/ 22 марта 2012

Я пытаюсь сделать простой запрос сериализованного столбца, как вы это делаете?

serialize :mycode, Array


1.9.3p125 :026 > MyModel.find(104).mycode
  MyModel Load (0.6ms)  SELECT `mymodels`.* FROM `mymodels` WHERE `mymodels`.`id` = 104 LIMIT 1
 => [43565, 43402] 
1.9.3p125 :027 > MyModel.find_all_by_mycode("[43402]")
  MyModel Load (0.7ms)  SELECT `mymodels`.* FROM `mymodels` WHERE `mymodels`.`mycode` = '[43402]'
 => [] 
1.9.3p125 :028 > MyModel.find_all_by_mycode(43402)
  MyModel Load (1.2ms)  SELECT `mymodels`.* FROM `mymodels` WHERE `mymodels`.`mycode` = 43402
 => [] 
1.9.3p125 :029 > MyModel.find_all_by_mycode([43565, 43402])
  MyModel Load (1.1ms)  SELECT `mymodels`.* FROM `mymodels` WHERE `mymodels`.`mycode` IN (43565, 43402)
 => [] 

Ответы [ 7 ]

70 голосов
/ 28 января 2013

Это просто хитрость, чтобы не замедлять работу вашего приложения. Вы должны использовать .to_yaml.

точный результат:

MyModel.where("mycode = ?", [43565, 43402].to_yaml)
#=> [#<MyModel id:...]

Проверено только для MySQL.

37 голосов
/ 22 марта 2012

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

Тем не менее, один очень хороший способ замедлить ваше приложение для сканирования может быть:

MyModel.all.select { |m| m.mycode.include? 43402 }

Мораль истории: не используйте #serialize для каких-либо данных, к которым вам нужно обратиться.

31 голосов
/ 08 марта 2013

Сериализованный массив хранится в базе данных определенным образом, например:

[1, 2, 3, 4]
in
1\n 2\n 3\n etc

следовательно, запрос будет

MyModel.where("mycode like ?", "% 2\n%")

поставить пробел между % и 2.

17 голосов
/ 04 ноября 2012

Ответ Noodl правильный, но не совсем правильный.

Это действительно зависит от используемого вами адаптера базы данных / ORM: например, PostgreSQL теперь может хранить и искать хэши / json - проверьте hstore.Я помню, что читал, что адаптер ActiveRecord для PostgreSQl теперь обрабатывает его правильно.И если вы используете mongoid или что-то в этом роде - тогда вы используете неструктурированные данные (например, json) на уровне базы данных повсюду.

Однако, если вы используете базу данных, которая не может действительно обрабатывать хэши - как MySQLКомбинация / ActiveRecord - тогда единственная причина, по которой вы бы использовали сериализованное поле, - это некоторые данные, которые вы можете создавать / записывать в некотором фоновом процессе и отображать / выводить по требованию - только два использования, которые я обнаружил в своем опыте, - это некоторые отчеты (напримерПоле статистики в модели продукта - где мне нужно хранить некоторые средние и средние значения для продукта) и пользовательские параметры (например, предпочитаемый ими цвет шаблона - мне действительно не нужно запрашивать это) - однако пользовательская информация - например, их подпискадля списка рассылки - должен быть доступен поиск по электронной почте.

PostgreSQL hstore ActiveRecord Пример:

MyModel.where("mycode @> 'KEY=>\"#{VALUE}\"'")

ОБНОВЛЕНИЕ Начиная с 2017 года MariaDB и MySQL поддерживают типы полей JSON.

8 голосов
/ 23 апреля 2015

Хорошие новости!Если вы используете PostgreSQL с hstore (что очень легко с Rails 4), теперь вы можете полностью искать сериализованные данные. Это - удобное руководство, а здесь - это документация по синтаксису от PG.

В моем случае у меня есть словарь, который хранится в виде хэша в столбце hstore и называетсяamenities.Я хочу проверить пару запрашиваемых удобств, которые имеют значение 1 в хэше, я просто

House.where("amenities @> 'wifi => 1' AND amenities @> 'pool => 1'")

Ура для улучшений!

7 голосов
/ 17 февраля 2013

Вы можете запросить сериализованный столбец с помощью оператора SQL LIKE.

 MyModel.where("mycode LIKE '%?%'", 43402)

Это быстрее, чем использование include?, Однако вы не можете использовать массив в качестве параметра.

3 голосов
/ 20 сентября 2017

Есть сообщение от 2009 г. от FriendFeed в блоге, в котором описано, как использовать сериализованные данные в MySQL.

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

Создайте модель, содержащую доступные для поиска значения / поля

В вашем примере модели будут выглядеть примерно так:

class MyModel < ApplicationRecord
  # id, name, other fields...
  serialize :mycode, Array
end

class Item < ApplicationRecord
  # id, value...
  belongs_to :my_model
end

Создание индексаТаблица для доступных для поиска полейпросто выполните запрос и выполните поиск: Item.where(value: [43565, 43402]).all.map(&:my_model) Item.where(value: 43402).all.map(&:my_model) Вы можете добавить метод в MyModel, чтобы упростить его: def find_by_mycode(value_or_values) Item.where(value: value_or_values).all.map(&my_model) end MyModel.find_by_mycode([43565, 43402]) MyModel.find_by_mycode(43402) Чтобы ускорить процесс, вы захотите создать индекс SQL дляэтот стол.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...