json JQMap和合并

kupeojn6  于 2023-08-08  发布在  其他
关注(0)|答案(2)|浏览(111)

当我根据一个值对对象进行分组和添加(读作合并)时,我希望将某些属性连接在一起,而不是默认的“右边的对象获胜”行为。
demo
换句话说,我想添加/合并这两个对象

[
  {
    "location": "apc1",
    "type": "app",
    "fgrp": "cert-apc-1"
  },
  {
    "location": "apc1",
    "type": "ctl",
    "cgrp": "ctl-apc1"
  }
]

字符串
来制作这个

[
  {
    "location": "apc1",
    "type": "app,ctl",
    "fgrp": "cert-apc-1",
    "cgrp": "ctl-apc1"
  }
]


尝试了group_by(.location) | map(add),但如前所述,它基本上只保留最后一个值。也看了转置,但不确定它是否符合要求。此外,如果其他东西更容易,我不会嫁给逗号作为分隔符。

doinxwow

doinxwow1#

您可以编写自定义合并操作。例如,先遍历所有项,然后遍历每个项的字段,并在相应的.location值下的字段名称下收集数组中的所有值。最后,修复.location数组,方法是仅将它们替换为first项:

reduce .[] as $item ({};
  reduce ($item | to_entries[]) as $ent (.;
    .[$item.location][$ent.key] += [$ent.value]
  )
) | map(.location |= first)

个字符
Demo
更进一步,您可以使用join和粘合字符串(这里是",")连接数组值。在此之前,准备.location的修复,以匹配join的类型要求(仅接受数组):

reduce .[] as $item ({};
  reduce ($item | to_entries[]) as $ent (.;
    .[$item.location][$ent.key] += [$ent.value]
  )
) | map(.location |= [first] | .[] |= join(","))
[
  {
    "location": "apc1",
    "type": "app,ctl",
    "fgrp": "cert-apc-1",
    "cgrp": "ctl-apc1"
  }
]

的字符串
Demo
为了方便起见,现在可以将这个过滤器 Package 到一个函数定义中,并将其动态部分(索引和连接表达式)参数化:

def merge(idx_expr; join_expr):
  reduce .[] as $item ({};
    reduce ($item | to_entries[]) as $ent (.;
      .[$item | idx_expr][$ent.key] += [$ent.value]
    )
  ) | map(join_expr);

merge(.location; .location |= [first] | .[] |= join(","))
[
  {
    "location": "apc1",
    "type": "app,ctl",
    "fgrp": "cert-apc-1",
    "cgrp": "ctl-apc1"
  }
]

的字符串
Demo
或者给予你的函数一个更通用的字符,从它排除最终的Map,所以它产生一个对象(不是数组),索引作为键,因此更像group_by的数组值变体(在处理索引字段时也没有区别,毕竟它可以是任何索引表达式,而不仅仅是一个公共字段的值):

def merge_by(f):
  reduce .[] as $item ({};
    reduce ($item | to_entries[]) as $ent (.;
      .[$item|f][$ent.key] += [$ent.value]
    )
  );

merge_by(.location)
{
  "apc1": {
    "location": [
      "apc1",
      "apc1"
    ],
    "type": [
      "app",
      "ctl"
    ],
    "fgrp": [
      "cert-apc-1"
    ],
    "cgrp": [
      "ctl-apc1"
    ]
  }
}

Demo

tjvv9vkg

tjvv9vkg2#

尝试了group_by(.location) | map(add),但如前所述,它基本上只保留最后一个值。
按照这种基于group_by的更实用的方法,您可以使用一个自定义函数来替换add,该函数首先将其输入数组(分组对象)分解为路径值对流,然后翻转每个路径数组中的前两个位置(从[position,field name]到[field name,position]),然后再次组合。结果是一个对象(字段名称移动到第一个位置),其项目包含该组中该字段值的Map(在相应项目没有该字段的位置使用null(或更短的数组))。因此,后续的join也需要将数组减少到只包含非空的values

def merge: fromstream(tostream | first[:2] |= reverse)
  | .location |= .[:1] | .[] |= (map(values) | join(","));

group_by(.location) | map(merge)

个字符
Demo

相关问题