且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用jq用另一个json文件中的对象覆盖json文件

更新时间:2023-01-08 12:15:38

以下是使用

Here is a solution which uses Object Multiplication. Assuming your data is in A.json and B.json:

$ jq -M --argfile b B.json '.[0].elements[0] *= $b[0].elements[0]' A.json

产生

[
  {
    "uri": "https://someurl.com",
    "id": "some-id",
    "keyword": "SomeKeyword",
    "name": "Some Name",
    "description": "Some description for that test result",
    "line": 2,
    "tags": [
      {
        "name": "@sometag",
        "line": 1
      }
    ],
    "elements": [
      {
        "a": 5,
        "b": 2
      }
    ]
  }
]

如果您的数组包含更多数据,则很容易推广这种方法,但是您需要了解如何识别相应的元素.

This approach is easily generalized if your arrays contain more data but you'll need to understand how corresponding elements should be identified.

关于修订后的问题,这是一个过滤器,该过滤器用具有相同 .id的 B.json 的相应对象更新 A.json 的对象.代码>:

Regarding the revised question, here is a filter which updates objects of A.json with corresponding objects of B.json having the same .id:

def INDEX(stream; idx_expr):
  reduce stream as $row ({};
    .[$row|idx_expr| if type != "string" then tojson else . end] |= $row);

def merge_by_id(a;b):
  if b then INDEX(a[];.id) * INDEX(b[];.id) | map(.) else a end;

  INDEX($b[];.id) as $i
| map( .elements = merge_by_id(.elements; $i[.id].elements) )

例如,如果上述过滤器位于 filter.jq 中,则 A.json 包含修订后的示例数据,而 B.json 包含

For example if the above filter is in filter.jq, A.json contains the revised sample data and B.json contains

[
  {
    "id": "safety-tests",
    "elements": [
      {
        "id": "some-element-id",
        "description": "updated description"
      }
    ]
  }
]

命令

$ jq -M --argfile b B.json -f filter.jq A.json

生成结果

[
  {
    "uri": "some/url.feature",
    "id": "safety-tests",                      <------ top level .id
    ...
    "elements": [
      {
        "id": "some-element-id",               <------ element .id
        "keyword": "Scenario Outline",
        "name": ": Some scenario name",
        "description": "updated description",  <------ updated value
        "line": 46,
        "type": "scenario",
        ...


请注意,上述解决方案假定 A.json 中元素的 .id 是唯一的,否则 merge_by_id 不会产生所需的输出.在这种情况下,以下过滤器就足够了:


Note that the above solution assumes the .id of the elements in A.json are unique otherwise merge_by_id won't produce the desired output. In that case the following filter should suffice:

def INDEX(stream; idx_expr):
  reduce stream as $row ({};
    .[$row|idx_expr| if type != "string" then tojson else . end] |= $row);

  (INDEX($b[];.id) | map_values(INDEX(.elements[];.id))) as $i
| map( $i[.id] as $o | if $o then .elements |= map($o[.id]//.) else . end )

此过滤器仅要求 B.json 中的对象的 .id 是唯一的.如果 A.json B.json 中都可能存在非唯一元素,则需要更复杂的映射.

This filter only requires the .id of the objects in B.json to be unique. If it's possible for there to be non-unique elements in both A.json and B.json then a more sophisticated mapping then this one will be required.

以下是带有注释的过滤器版本:

Here is a version of the filter with comments:

def INDEX(stream; idx_expr):
  reduce stream as $row ({};
    .[$row|idx_expr| if type != "string" then tojson else . end] |= $row);

  # first create a lookup table for elements from B.json
  (                                         #       [{id:x, elements:[{id:y, ...}]}]
      INDEX($b[];.id)                       # -> {x: {id:x, elements:[{id:y, ...}]}..}
    | map_values(INDEX(.elements[];.id))    # -> {x: {y: {id:y, ...}}}
  ) as $i

  # update A.json objects
| map(                                      # for each object in A.json
    $i[.id] as $o                           # do we have updated values from B.json ?
  | if $o then .elements |= map($o[.id]//.) # if so then replace corresponding elements
    else . end                              # otherwise leave object unchanged
  )