【问题标题】:How to access Chewy results with the dot notation?如何使用点符号访问 Chewy 结果?
【发布时间】:2018-08-31 20:37:24
【问题描述】:

我正在使用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) 访问嵌套关联?或者反序列化对象(例如结构)中的嵌套数据,这允许我使用点表示法?

【问题讨论】:

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


    【解决方案1】:

    尝试使用

    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 链接

    【讨论】:

    • 它只查询最终结果对象。不是确切的 ES 查询
    • 将其转换为 ruby​​ 哈希到 openStruct 对象,因为哈希没有 .dot 语法
    • 它适用于一些修改检查这个 mystr = JSON.parse(json_data,object_class: OpenStruct)
    • 我已经更新了我的最终答案以适用于嵌套对象。你可以接受。如果它适合你。
    • 我提出了另一种解决方案。似乎更有表现力。
    【解决方案2】:

    将刚刚反序列化的结果转换为 JSON 字符串并使用 OpenStruct 将其再次反序列化为 object_class 可能是个坏主意,而且 CPU 成本很高。

    我使用递归和 Ruby 的原生 Struct 以不同的方式解决了这个问题,保留了 Chewy gem 的惰性。

    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::LazyEnumerator#map。将 ES 查询返回的每个值映射到 convert_to_object 函数中,使每个条目成为一个完整的结构。

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

    【讨论】:

      猜你喜欢
      • 2018-06-10
      • 1970-01-01
      • 1970-01-01
      • 2022-09-27
      • 2013-01-23
      • 1970-01-01
      • 1970-01-01
      • 2016-01-04
      • 2013-01-20
      相关资源
      最近更新 更多