Jq - 计算 JSON 中每个数组的长度并更新它

Inv*_*999 7 arrays select json jq

我有以下 JSON 数组

[
  {
    "name": "California",
    "Data": {
      "AB00001": ["Los Angeles", "San Francisco", "Sacramento", "Fresno", "San Jose", "Palo Alto"]
    }
  },
  {
    "name": "Oregon",
    "Data": {
      "CD00002": ["Portland", "Salem", "Hillsboro"]
    }
  },
  {
    "name": "Washington",
    "Data": {
      "EF00003": ["Seattle", "Tacoma", "Spokane", "Bellevue"]
    }
  }
]
Run Code Online (Sandbox Code Playgroud)

我可以获取jq '.[].Data[] | length'每个数组的长度,但我需要在对象Length下创建键Data并为其分配数据对象中数组的长度。结果应如下所示:

[
    {
        "name": "California",
        "Data": {
            "ID00001": ["Los Angeles", "San Francisco", "Sacramento", "Fresno", "San Jose", "Palo Alto"],
            "Length": 6
        }
    },
    {
        "name": "Oregon",
        "Data": {
            "ID00002": ["Portland", "Salem", "Hillsboro"],
            "Length": 3
        }
    },
    {
        "name": "Washington",
        "Data": {
            "ID00003": ["Seattle", "Tacoma", "Spokane", "Bellevue"],
            "Length": 4
        }
    }
]
Run Code Online (Sandbox Code Playgroud)

这里的问题是,在我的示例中,保存数组的对象名称(Data在我的示例中)和数组名称本身 ( AB00001/CD00002/EF00003) 是事先未知的。然而,键的值name是已知的。另外,数组可能为空,因此在这种情况下,Length应该为 0。

因此,算法伪代码应该是我所设想的其中之一:

for the whole JSON file, 
if the type is an array, 
then assign it to the Length key created in the parent object of that array, 
next
Run Code Online (Sandbox Code Playgroud)

或者

For the specific value in the name key, select,
if the entry contains an array
create Length key in the array's parent object, 
assign the length of the array,
select the next value of the name key
Run Code Online (Sandbox Code Playgroud)

我尝试与 jqwalk..第一种方法一起使用,但没有成功。有哪些替代方案?

pea*_*eak 9

解决当前问题(其中 .Data 是一个带有数组值键的单键对象)的解决方案可能很简单:

map( .Data.Length = (.Data[]|length) )
Run Code Online (Sandbox Code Playgroud)

这可以逐步适应更普遍的问题。首先,考虑一下这个概括:

map( .Data |= if length==1 and (.[]|type) == "array" 
              then .Length = (.[]|length) 
              else . end )
Run Code Online (Sandbox Code Playgroud)

解决方案

为了使实际的解决方案更容易理解,让我们定义一个辅助函数:

def addLength:
   (first(keys_unsorted[] as $k
          | select(.[$k]|type == "object")
          | .[$k]
          | keys_unsorted[] as $l 
          | select(.[$l]|type == "array")
          | [$k,$l]) // null) as $a
   | if $a 
     then setpath([$a[0],"Length"]; getpath($a)|length)
     else .
     end;
Run Code Online (Sandbox Code Playgroud)

现在可以使用以下方法编写通用解决方案walk

walk(if type == "object" and has("name")
     then addLength
     else . end)
Run Code Online (Sandbox Code Playgroud)