Как получить доступ к результатам Chewy с помощью точечной нотации? - PullRequest
0 голосов
/ 30 августа 2018

Я использую Chewy gem Топтала для подключения и запроса моего 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 ]

0 голосов
/ 31 августа 2018

Преобразование только что десериализованных результатов в строку JSON и повторная десериализация их с помощью OpenStruct как object_class может быть плохой идеей и имеет большую стоимость процессора.

Я решил это по-другому, используя рекурсию и нативный Ruby Struct, сохранив лень драгоценного камня Chewy.

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 делает каждую запись полной структурой.

Код очень общий и работает с каждым индексом, который у меня есть.

0 голосов
/ 30 августа 2018

попробуйте использовать

results = OrdersIndex.query(query_string: { query: "test" }).objects

Преобразует результат запроса в активную запись объектов. поэтому точечная запись должна работать. Если вы хотите загрузить какую-либо дополнительную связь с приведенным выше результатом, вы можете использовать метод .load в Index.

Если вы хотите преобразовать существующий вложенный объект ES в доступный с точечной нотацией, попробуйте сослаться на этот ответ. Open Struct - лучший способ сделать все в ruby.

Невозможно использовать точечный синтаксис для хэша ruby ​​

также, это тоже можно помочь

см. эту ссылку, если вам нужен openStruct для работы с вложенным объектом

...