我正在使用Ruby on rails,我有两个SQL查询,每个查询都返回一个对象array.这两个SQL查询来自两个独立的数据库,因此它们具有不同的字段,然而,我应该将结果合并到一个列表中.下面是两个SQL查询的示例以及最终结果应该是什么样子.

SQL1 result == [{id1: 1, name: john, role: user},{id1: 2, name: matt, role: admin}]
SQL2 result == [{id2: 4, externalName: john},{id2: 8, externalName: ronald}]

我们希望将名称==外部名称的任何对象合并为一个对象,但保持其他对象不变.

RESULT == [{id1: 1, name: john, role: user, id2: 4},{id1: 2, name: matt, role: admin},{id2: 8, externalName: ronald}]

基本上,我希望将两个列表添加在一起,但是,当第二个列表中的:ExteralName等于第一个列表中的:Name值或相反时,我们希望将这两个单独的对象合并为一个对象,因为它们将被视为"重复的".两个对象的组合结果将类似于{:id1, :name, :role, :id2}.不满足此条件的其余对象仍将出现在结果数组中.

我已经完成了一次连接,它只是将两个数组添加到一个很好的数组中,但是它不会在name==外部名称上合并.我曾考虑过使用.merge(),但不确定如何对两个完整的对象数组执行此操作,以及如果不满足合并条件会发生什么,这些对象是否仍会出现在结果列表中.我也考虑过映射,但在将结果对象合并到另一个对象后,需要弄清楚如何将其删除.我不确定现在最好的方法是什么,只是在寻找一些小贴士.

推荐答案

您可以按如下方式执行此操作:

sql1 = [{id1: 1, name: 'john', role: 'user'},{id1: 2, name: 'matt', role: 'admin'}]
sql2 = [{id2: 4, externalName: 'john'},{id2: 8, externalName: 'ronald'}]
[*sql1,*sql2]
  .group_by { |h| h[:name] || h[:externalName] }
  .flat_map do |k,v| 
     v.reduce(&:merge).tap { |h| h.delete(:externalName) if h.key?(:name) }
  end
#=> => [{:id1=>1, :name=>"john", :role=>"user", :id2=>4}, {:id1=>2, :name=>"matt", :role=>"admin"}, {:id1=>17, :role=>"user"}, {:id2=>8, :externalName=>"ronald"}]

步骤:

  • [*sql1,*sql2]-合并两个数组

  • .group_by {|h| h[:name] || h[:externalName]}-如果h[:name]为假,则按值:name:externalName对元素进行分组(在本例中假定为nil)

  • map do |_,v|-将根据块的返回值返回一个新的数组,当在Hash上调用(由group_by返回)时,它将为块产生键和值.在这种情况下,我们不关心密钥,所以我们使用_来表示这一点.

    • v.reduce(&:merge) -将值合并为单个Hash
    • tap { |h| h.delete(:externalName) if h.key?(:name) }-tap将结果Hash产生给块,并且如果Hash具有name密钥,则我们删除:externalName密钥.此块将始终返回生成的对象.

Update 显然,name不是必需的键,这导致了一个由nil个值组成的大组,其中合并缩减不是一个选项.更新了处理nil分组的代码.

sql1 = [{id1: 1, name: 'john', role: 'user'},{id1: 2, name: 'matt', role: 'admin'}, {id1: 17, role: 'user'}, {id1: 12, role: 'admin'} ]
sql2 = [{id2: 4, externalName: 'john'},{id2: 8, externalName: 'ronald'}, {id2: 42}]
[*sql1,*sql2]
  .group_by { |h| h[:name] || h[:externalName] }
  .flat_map do |k,v| 
     next v unless k
     v.reduce(&:merge).tap { |h| h.delete(:externalName) if h.key?(:name) }
  end
#=> [{:id1=>1, :name=>"john", :role=>"user", :id2=>4}, {:id1=>2, :name=>"matt", :role=>"admin"}, {:id1=>17, :role=>"user"}, {:id1=>12, :role=>"admin"}, {:id2=>42}, {:id2=>8, :externalName=>"ronald"}]

Other Assumptions

以下是基于员额的假设:

  • sql1中没有重复的名称或sql2中没有重复的externalNames(导致最大组为2;sql1中值为1,sql2中值为1)
  • sql1sql2之间没有重叠的关键点.否则,结果值将为sql2

Ruby-on-rails相关问答推荐

ActiveRecord::声明在类别中无效#new

Rails - 如何从模型中查询 has_many

ActiveRecord 错误地转义 JSON 字符串

只允许用户在 Rails 中输入字母和数字

为 has_attached_file 等活动记录属性创建类方法

Ruby 地理定位Ruby /插件

Rails 模型.有效吗?刷新自定义错误并错误地返回 true

Rails 3 远程表单:如何指定内容类型?

你能从 Heroku dynos/workers 中获得多少性能?

rake assets:precompile try 连接到数据库

Rails 发现获取 ActiveRecord::RecordNotFound

价格字段的字符串、小数或浮点数据类型?

带有查询字符串参数的 Rails 动作缓存

Rails:仅当值存在时如何验证格式?

Rails 3. 构建 oauth2 提供程序

Ruby 和 Ruby on Rails 离线 API 文档

rails 4 before_validation on: :create 或 on: :save

登录delay_job?

如何强制 RSpec 测试失败?

为什么 Google Oauth 在我的 Rails 应用程序中返回无效的 redirect_urI?