Поиск сериализованных данных с использованием активной записи
Я пытаюсь сделать простой запрос сериализованного столбца, как вы это делаете?
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)
=> []
Ответы
Ответ 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 для этой таблицы.