Как получить доступ к результатам Chewy с помощью точечной нотации?
Я использую драгоценный камень Toptal Chewy для подключения и запроса моего Elasticsearch, как ODM.
Я использую Chewy вместе с Elasticsearch 6, Ruby on Rails 5.2 и Active Record.
Я определил свой индекс так:
class OrdersIndex < Chewy::Index
define_type Order.includes(:customer) do
field :id, type: "keyword"
field :customer do
field :id, type: "keyword"
field :name, type: "text"
field :email, type: "keyword"
end
end
end
И моя модель:
class Order < ApplicationRecord
belongs_to :customer
end
Проблема здесь в том, что когда я выполняю любой запрос с использованием Chewy, данные клиента десериализуются как хэш вместо Object, и я не могу использовать точечную запись для доступа к вложенным данным.
results = OrdersIndex.query(query_string: { query: "test" })
results.first.id
# => "594d8e8b2cc640bb78bd115ae644637a1cc84dd460be6f69"
results.first.customer.name
# => NoMethodError: undefined method `name' for #<Hash:0x000000000931d928>
results.first.customer["name"]
# => "Frederique Schaefer"
Как я могу получить доступ к вложенной ассоциации с помощью точечной нотации (result.customer.name
)? Или десериализовать вложенные данные внутри объекта, такого как структура, что позволяет мне использовать точечную запись?
2 ответа
Попробуй использовать
results = OrdersIndex.query(query_string: { query: "test" }).objects
Он преобразует результат запроса в объекты активной записи. поэтому точечная запись должна работать. Если вы хотите загрузить дополнительную связь с приведенным выше результатом, вы можете использовать метод.load в Index.
Если вы хотите преобразовать существующий вложенный объект ES в доступный с точечной нотацией, попробуйте обратиться к этому ответу. Open Struct - лучший способ сделать все в рубине.
Невозможно использовать точечный синтаксис для хэша ruby
Кроме того, этот тоже может помочь
см. эту ссылку, если вам нужно openStruct для работы с вложенным объектом
Преобразование только что десериализованных результатов в строку JSON и повторную десериализацию с помощью OpenStruct как object_class
может быть плохой идеей и имеет большую стоимость процессора.
Я решил это по-другому, используя рекурсию и родной Ruby Struct
сохраняя лень жевательной жемчужины.
def convert_to_object(keys, values)
schema = Struct.new(*keys.map(&:to_sym))
object = schema.new(*values)
object.each_pair do |key, value|
if value.is_a?(Hash)
object.send("#{key}=", convert_to_object(value.keys, value.values))
end
end
object
end
OrdersIndex.query(query_string: { query: "test" }).lazy.map do |item|
convert_to_object(item.attributes.keys, item.attributes.values)
end
convert_to_object
берет массив ключей и еще одно из значений и создает из него структуру. Всякий раз, когда класс одного из элементов массива значений представляет собой хэш, он рекурсивно преобразуется в структуру, передавая ключи и значения хеш-функции.
Для присутствия лень, это самая крутая часть Chewy, я использовал Enumerator::Lazy
а также Enumerator#map
, Отображение каждого значения, возвращаемого запросом ES, в convert_to_object
функция, делает каждую запись полной структурой.
Код очень общий и работает с каждым индексом, который у меня есть.