如何使用jq将项目映射到json结构中?

如何使用jq将项目映射到json结构中?,json,path,jq,Json,Path,Jq,我有一个json结构,如下所示: { "lorry1": { "box1": [ {"item": "shoes", "state": "new"}, {"item": "snacks", "state": "new"} ], "box2": [

我有一个json结构,如下所示:

{
        "lorry1": {
                "box1": [
                        {"item": "shoes", "state": "new"},
                        {"item": "snacks", "state": "new"}
                ],
                "box2": [
                        {"item": "beer", "state": "cold"},
                        {"item": "potatoes"}
                ]
        },
        "lorry2": {
                "box1": [
                        {"item": "shoes", "state": "new"},
                        {"item": "snacks", "state": "new"}
                ],
                "box2": [
                        {"item": "beer", "state": "lukewarm"}
                ]
        }
}
"shoes": [ {"lorry1", "box1"}, {"lorry2", "box1" } ],
"snacks": [ {"lorry1", "box1"}, {"lorry2", "box1"} ],
"beer": [ {"lorry1", "box2"}, {"lorry2", "box2"} ],
"potatoes": [ {"lorry1", "box2"} ]
现在我想知道在哪里可以找到鞋子: 我可以提出以下jq问题:

to_entries | select(.[].value | .[][].item=="shoes") | map({"lorry": "\(.key)"  })
但那只给了我卡车。有用,但还不完全有用。我也想知道他们在哪个盒子里

我想到了这个,但显然是不正确的:

to_entries | select(.[].value | .[][].item=="shoes") | keys as $box |map({"lorry": "\(.key)", "box": $box })
我想得到的答案是lorry1,box1和lorry2,box1

更好的是:我希望找到所有项目并提供信息,如下所示:

{
        "lorry1": {
                "box1": [
                        {"item": "shoes", "state": "new"},
                        {"item": "snacks", "state": "new"}
                ],
                "box2": [
                        {"item": "beer", "state": "cold"},
                        {"item": "potatoes"}
                ]
        },
        "lorry2": {
                "box1": [
                        {"item": "shoes", "state": "new"},
                        {"item": "snacks", "state": "new"}
                ],
                "box2": [
                        {"item": "beer", "state": "lukewarm"}
                ]
        }
}
"shoes": [ {"lorry1", "box1"}, {"lorry2", "box1" } ],
"snacks": [ {"lorry1", "box1"}, {"lorry2", "box1"} ],
"beer": [ {"lorry1", "box2"}, {"lorry2", "box2"} ],
"potatoes": [ {"lorry1", "box2"} ]

但这可能要求有点太高了:)

这对我来说似乎有些过分,但它确实起到了作用

[path(.[][][].item) as $p | [$p, getpath($p)]] |
group_by( .[1] ) |
map({(.[0][1]): (. | map([.[0][0,1]]))})|
add
将上述
jq
过滤器保存在.jq中的文件
item\u中,并将其作为
jq--from.jq中的文件item\u
运行。将您的输入传递给此将产生以下输出:

{
  "beer": [
    [
      "lorry1",
      "box2"
    ],
    [
      "lorry2",
      "box2"
    ]
  ],
  "potatoes": [
    [
      "lorry1",
      "box2"
    ]
  ],
  "shoes": [
    [
      "lorry1",
      "box1"
    ],
    [
      "lorry2",
      "box1"
    ]
  ],
  "snacks": [
    [
      "lorry1",
      "box1"
    ],
    [
      "lorry2",
      "box1"
    ]
  ]
}
最初的转换是从输入JSON树转储树叶及其路径。 看见

我想得到的答案是lorry1,box1和lorry2,box1

在这种情况下,您可以通过以下方式获得:

路径(..|选择(.item?=“shoes”))
返回:

["lorry1","box1",0]
["lorry2","box1",0]

这些是对象中指向对象的路径,该对象的
。item
属性设置为“shoes”

这里有一个通用解决方案,它不假设“items”在数组中,甚至与“item”键关联的值始终是字符串:

jq -c '. as $in
  | [paths as $p | select($p[-1] == "item") | $p]
  | group_by(. as $p | $in|getpath($p))
  | .[]
  | (.[0] as $p | $in | getpath($p)) as $v
  | {($v|tostring):  ( map(.[:-1] | if .[-1] | type == "number" then .[:-1] else . end)) }
'
输出 根据您的输入:

{"beer":[["lorry1","box2"],["lorry2","box2"]]}
{"potatoes":[["lorry1","box2"]]}
{"shoes":[["lorry1","box1"],["lorry2","box1"]]}
{"snacks":[["lorry1","box1"],["lorry2","box1"]]}

如果希望将输出作为单个JSON对象,则将上述内容收集到一个数组中,并使用
add

确定要以非JSON格式进行最终输出吗?因为
{“lorry1”,“box1”}而提问是无效的,JSONI确实应该写得更好。这个想法突然出现了。谢谢;它看起来也很可读,我真的很喜欢。这也有助于了解正确的术语:)一直在玩这个,看看我是否理解这里发生的事情,不是真正理解它,但我希望有一天会发生。。。谢谢很好的解决方案。由于这里的结构已知,您可以使用
path([][]].item)
简化路径提取,而不需要额外的
select
步骤。如果没有
(.|…)
,最终的
映射对我来说也会更具可读性。例如,您可以只编写
path(..| scalars)
而不是
path(leaves)
。谢谢@peak,我将更新答案。这将使它更加简洁。它的简洁性非常出色。我必须承认路径()对我来说有点神秘;哇。。。3个答案,每个答案都有自己的优点。我向你们大家鞠躬@Michiel,为了补充peak的一个优秀解决方案,让我也为您提供一个完整的替代方案(让您知道)-基于实用工具
jtc
(我是创建者)。使用
jtc
时,输入不变的解决方案将如下所示:
@Dmitry-在您的解决方案生成的JSON中,.potates不是数组数组的数组。@peak,它不是有点多余吗-一个数组的数组?但是,我可以设想一个论点:后续处理更容易,或者可能是下一步的要求。在这种情况下,可以使用选项集扩展解决方案,将数组封装添加到单个数组: