Подтвердить что ты не робот

Поиск сериализованных данных с использованием активной записи

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

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)
 => [] 
4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

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

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

PostgreSQL hstore Пример ActiveRecord:

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

Ответ 5

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

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

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

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

Ответ 6

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

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

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

Ответ 7

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

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

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

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

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

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

Создание таблицы "index" для полей поиска

Когда вы сохраняете MyModel, вы можете сделать что-то вроде этого, чтобы создать индекс:

Item.where(my_model: self).destroy
self.mycode.each do |mycode_item|
  Item.create(my_model: self, value: mycode_item)
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 для этой таблицы.