我正在使用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)中的嵌套数据,使我可以使用点符号?
答案 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::Lazy
和Enumerator#map
。将ES查询返回的每个值映射到convert_to_object
函数中,使每个条目成为完整的结构。
该代码非常通用,适用于我拥有的每个索引。