如何使用jq中的流选项从JSON文件中检索键和值

时间:2018-11-12 05:31:17

标签: json stream jq

我有一个结构如下的json文件:

 {
    "A": [{
        "B": {
            "C": [{
                "D": {
                    "applicationNumberText": {
                        "value": "15570075",
                        "electronicText": "15570075"
                    },
                    "date": "2018-10-01",
                    "app": "Utility"
                }
            }]
        }
    }]
}

现在,我想检索electronicText的值。一种方法是使用类似以下的索引

jq --stream 'select(.[0][1] == "A" and .[0][2] == "B" and .[0][3] == "C") | .[1]'

,但是结构在某些情况下可能会有所不同,因此我想通过键值而不是索引来引用。我尝试了以下方法,但无法正常工作

cat file.json | jq --stream 'select(.A|.[]. B. C|.[]. D.applicationNumberText)'

所以我想在不使用索引的情况下检索electronicText键。

Note:我想对大型JSON文件使用stream选项。

4 个答案:

答案 0 :(得分:1)

如果数组的索引是固定的,则可以使用此过滤器:

jq '.A[0].B.C[0].D.applicationNumberText.electronicText' file

并提取所有electronicText字段,可以使用以下方法:

jq '.A[].B.C[].D.applicationNumberText.electronicText' file

如果您想使用jq流方式(虽然不清楚原因),则可以使用以下方式:

jq --stream 'select(.[0]|contains(["electronicText"]))|.[1]//empty'

这将在字符串electronicText的键路径中查找,如果找到,则获取其关联值。 //empty将过滤掉没有值的路径数组。

答案 1 :(得分:1)

我相信您正在寻找的是:

$targetedCustomer = Customer::on($this->connection)->where('fusercode', $user->loginname)->first();
if($targetedCustomer->agent_code != $user->agent)
{
    $targetedCustomer->agent_code = $user->agent;
    $targetedCustomer->save();

    $logs = CustomerAgentCodeUpdateLog::on($this->connection);
    $logs->customer_id =  $targetedCustomer->customer_id;
    $logs->old_agent_code = $targetedCustomer->agent_code;
    $logs->new_agent_code = $user->agent;
    $logs->type = 1;
    $logs->save();
}

此过滤器期望. as $inputs | {} | setpath($inputs[0]; $inputs[1]) | .A[]?.B.C[]?.D.applicationNumberText.electronicText // empty 作为标志(如您的第一个示例),生成带有json部分的时间obj,根据第二个示例运行该过滤器,然后隐藏空结果。注意:This based on a example in the cookbook

让我概述一下正在发生的事情,以防万一:

  1. The --stream flag will make your receive your data differently。现在,您的过滤器将使用--stream格式的数据运行多次,当解析器遍历您的json文件时,它一次接收一个节点。

    我相信您在提及使用索引时会提及此情况,在这种情况下,这意味着您正在检查[<path>, <leaf-value>]公开的path expression value而不是 actual json数据

    请比较以下内容的输出:

    --streaming flag
  2. setpath()接收这些路径,并且叶值参数将其放在其输入对象的顶部。例如

    jq '.A[].B.C[].D.applicationNumberText.electronicText' file.json # outputs 15570075 
    jq --stream '.A[].B.C[].D.applicationNumberText.electronicText' file.json # multiple failures: cannot index array with string "A"
    

    在我们的案例中,当解析访问每个节点时,我们正在生成以下值流:

    {} | setpath(["a", 0, "b"], "leaf-value") # returns {"a":[{"b":"leaf-value"}]}
    
  3. 现在数据的格式类似于json文件,我们可以运行更熟悉的过滤器。

    {"A":[{"B":{"C":[{"D":{"applicationNumberText":{"value":"15570075"}}}]}}]}
    {"A":[{"B":{"C":[{"D":{"applicationNumberText":{"electronicText":"15570075"}}}]}}]}
    {"A":[{"B":{"C":[{"D":{"applicationNumberText":{"electronicText":null}}}]}}]}
    {"A":[{"B":{"C":[{"D":{"date":"2018-10-01"}}]}}]}
    {"A":[{"B":{"C":[{"D":{"app":"Utility"}}]}}]}
    

    请记住,两者之间没有空格。我们还在生成器.A[]?.B.C[]?.D.applicationNumberText.electronicText ?上都使用了.A[]运算符,因为我们不确定这些字段是否始终可作为数组使用

最后一点,您可能需要考虑使用path()构建路径数组,并在使用.C[] jq标志时将其与.[0]中显示的路径值进行比较

答案 2 :(得分:1)

针对原始问题:

jq --stream '
  select(length==2 and .[0][-1]=="electronicText")|.[1]
' input.json
"15570075"

如果您还需要value,则可能需要考虑以下过滤器:

select(length==2 and .[0][-2]=="applicationNumberText")
| .[0][-1] as $last
| select($last == "electronicText" or $last == "value")
| {($last): .[1]}

使用您的示例JSON生成的

{"value":"15570075"}
{"electronicText":"15570075"}

将键值对组合到单个JSON对象中

构造“词典”的一种方法是将inputs与-n命令行选项结合使用。只需将上述过滤器包装在结构中即可:

 [inputs | ....] | add

在这里..代表上述过滤器;并使用-n和--stream选项的 both 调用jq。

答案 3 :(得分:0)

如果您知道感兴趣对象的名称,只需按名称搜索对象路径。

getpath(paths(objects) | select(.[-1] == "applicationNumberText"))

以流方式输入应该有助于解决效率问题。只需确定要保留的路径并截断感兴趣的路径即可。

$ jq -n --stream --arg key 'applicationNumberText' '
fromstream(inputs | truncate_stream2((.[0] | index($key) // empty) + 1))
' input.json

这只是检查路径并寻找"applicationNumberText"键,然后将路径截断为该值,以便可以从流中重建它。

这使用了truncate_stream/1函数的反向版本,该函数交换了我使用更直观的常用输入。

def truncate_stream2($count): .[0] |= .[$count:];