首页 > 解决方案 > 使用 JQ(在所有级别上)使用来自另一个 JSON 的值更新一个 JSON 文件值

问题描述

我有两个 JSON 文件:

来源.json:

{
  "general": {
    "level1": {
      "key1": "x-x-x-x-x-x-x-x",
      "key3": "z-z-z-z-z-z-z-z",
      "key4": "w-w-w-w-w-w-w-w"
    },
    "another" : {
      "key": "123456",
      "comments": {
        "one": "111",
        "other": "222"
      }
    }
  },
  "title": "The best"
}

目标.json:

{
  "general": {
    "level1": {
      "key1": "xxxxxxxx",
      "key2": "yyyyyyyy",
      "key3": "zzzzzzzz"
    },
    "onemore": {
      "kkeeyy": "0000000"
    }
  },
  "specific": {
    "stuff": "test"
  },
  "title": {
    "one": "one title",
    "other": "other title"
  }
}

考虑到所有级别,我需要两个文件中存在的键的所有值,从source.json复制到target.json
我已经看到并测试了这篇文章中的解决方案。它只复制第一级密钥,我无法让它做我需要的事情。这篇文章中解决方案的结果如下所示:

{
  "general": {
    "level1": {
      "key1": "x-x-x-x-x-x-x-x",
      "key3": "z-z-z-z-z-z-z-z",
      "key4": "w-w-w-w-w-w-w-w"
    },
    "another": {
      "key": "123456",
      "comments": {
        "one": "111",
        "other": "222"
      }
    }
  },
  "specific": {
    "stuff": "test"
  },
  "title": "The best"
}

“通用”键下的所有内容都按原样复制。
我需要的是这样的:

{
  "general": {
    "level1": {
      "key1": "x-x-x-x-x-x-x-x",
      "key2": "yyyyyyyy",
      "key3": "z-z-z-z-z-z-z-z"
    },
    "onemore": {
      "kkeeyy": "0000000"
    }
  },
  "specific": {
    "stuff": "test"
  },
  "title": {
    "one": "one title",
    "other": "other title"
  }
}

只应复制“key1”和“key3”。不得删除目标 JSON
中的 密钥,也不得创建新密钥。

任何人都可以帮忙吗?

标签: jsonmergejq

解决方案


您可以采取的一种方法是获取每个输入的所有标量值的所有路径并获取设置的交点。然后从这些路径将值从源复制到目标。

首先,我们需要一个 intersect 函数(制作起来非常困难):

def set_intersect($other):
    (map({ ($other[] | tojson): true }) | add) as $o
    | reduce (.[] | tojson) as $v ({}; if $o[$v] then .[$v] = true else . end)
    | keys_unsorted
    | map(fromjson);

然后进行更新:

$ jq --argfile s source.json '
reduce ([paths(scalars)] | set_intersect([$s | paths(scalars)])[]) as $p (.;
    setpath($p; $s | getpath($p))
)
' target.json

推荐阅读