根据特定键提取字符串值数组

时间:2018-10-16 10:02:57

标签: json jq

我希望每个人都好。

我正与JQ苦苦挣扎,试图使用特定键从输入json中选择字符串值数组。可以将“ key”:[“ string1”,...,“ stringn”]嵌入到json中任何深度的“某处”。我只知道数组的键值。

比方说,我有一些json,其中包含键dictionnay(字典)和json源(源)。在此示例中,我想选择“ key4”和“ key11”数组,并将它们与相应的键一起放入结果json中。

我的示例输入是:

 {
    "dict": ["key4", "key11"],
    "source":{
    "key0": {
        "key1": "valueA",
        "key2": 123456,
        "key3": [{
                "key4": ["anotherValue4341", "anotherValue4342"],
                "key5": [{
                    "someKey351": "someValue351"
                }, {
                    "someKey352": "someValue352"
                }],
                "key6": 999
            },
            {
                "key7": "anotherValue342",
                "key8": "anotherValue352",
                "key9": 666
            }
        ],
        "key10": {
            "key11": ["lastvalue111", "lastvalue112", "lastvalue113"]
        }
    }

}}

我对此样本的预期输出为:

{
    "key4": ["anotherValue4341", "anotherValue4342"],
    "key11": ["lastvalue111", "lastvalue112", "lastvalue113"]
}

我正在使用JQ提取请求的输出。

现在,我尝试重用以前的查询来选择键/值,如下所示:

jq '.dict as $dict | .source | reduce paths as $p (.;getpath($p) as $v| if $v|type == "string" and $dict[$v] then setpath($p; $dict[$v]) else . end)'

但是似乎它在某些值上苦苦挣扎:jq:错误(在26处):无法使用字符串“ valueA”索引数组

我还试图选择包含dict中键的匹配对象:

jq '.dict as $dict | .source | recurse(.[]?) | objects | select(in($dict))'

但这会导致错误“无法检查数组是否具有对象键”

我希望我足够清楚地解释我的需求/问题。

任何提示表示赞赏。

3 个答案:

答案 0 :(得分:1)

为简单起见,让我们首先假设核心任务是获取与 一个特定的密钥。为了说明和清楚起见,让我们相应地定义一个函数:

# Emit a (possibly empty) stream of key-value objects 
# corresponding to the $key specified as a string
def getKeyValue($key):
  .. | objects | select(has($key)) | {($key): .[$key]};

现在解决该问题的方法很简单:

[.dict[] as $k | getKeyValue($k)] | add

变化

此解决方案有几个潜在问题:

  • 输入中可能根本没有出现一个或多个感兴趣的键;

  • 一个或多个感兴趣的键可能在输入中出现多次;

  • 如果输入很大,则更有效的解决方案可能是可取的。

前两个问题很容易处理,但具体细节取决于具体要求。 同样,可以通过修改getKeyValue的def轻松解决效率问题,以便 命名参数是一个字符串数组。

答案 1 :(得分:1)

作为一种学习经验(对我们俩来说),这是一个类似于您上一个示例的版本:

.source as $source 
| [ 
  .dict[] | . as $key 
  | $source | .. 
  | select(.[$key]?) 
  | { ($key): .[$key]? } 
] | add

.source开始捕获$source,然后在.dict[]上进行迭代,将其中的每个键都别名为$key。然后,它切换回$source并在其上递归(使用..,它是recurse(.[]?)的短版。然后select查找带有键的任何子对象名为$key的对象构造函数将提取该键/值对,最后add将所有这些对象合并为一个。

我不保证它比其他解决方案更好或更快速,但这只是说明性的:)

答案 2 :(得分:0)

制作一个递归函数。像

function {
    foreach $array as $key => $value {
        if ($key == KEYYOUWANT) {
           $answer = value
           break;
       } else {
            function($value)
       }
    }
}

对不起,您的sudo代码!