如何用点号访问Chewy结果?

时间:2018-08-30 19:55:03

标签: ruby-on-rails ruby chewy-gem

我正在使用Toptal's 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执行任何查询时,客户数据将被反序列化为散列而不是对象的哈希,并且我无法使用点表示法来访问嵌套数据。

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)访问嵌套的关联?还是要反序列化对象(例如Struct)中的嵌套数据,使我可以使用点符号?

2 个答案:

答案 0 :(得分:2)

尝试使用

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

它将查询结果转换为活动记录对象。所以点符号应该起作用。如果要与上述结果加载任何额外的关联,可以在Index上使用.load方法。

如果要将现有的ES嵌套对象转换为点标记可访问,请尝试参考此答案。 Open Struct是用ruby完成任务的最好方法。

Unable to use dot syntax for ruby hash

另外,this也可以提供帮助

如果需要openStruct来处理嵌套对象,请参见this链接

答案 1 :(得分:0)

将刚反序列化的结果转换为JSON字符串,然后使用OpenStruct作为object_class再次反序列化可能是一个坏主意,并且会占用大量CPU。

我使用递归和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接受一组键和另一个值,并从中创建一个结构。每当值项数组之一的类为Hash时,它就会递归地传递给散列键和值,从而将其转换为结构。

为了表现懒惰,这是Chewy最酷的部分,我使用了Enumerator::LazyEnumerator#map。将ES查询返回的每个值映射到convert_to_object函数中,使每个条目成为完整的结构。

该代码非常通用,适用于我拥有的每个索引。