извлечь массив строковых значений на основе определенных ключей - PullRequest
0 голосов
/ 16 октября 2018

Надеюсь, у всех все хорошо.

Я борюсь с JQ, пытаясь выбрать массив значений строк из входного json, используя определенные клавиши для выбора.«Ключ»: [«string1», ..., «stringn»] может быть вставлен «где-то» на любую глубину в json.Я знаю только значения ключей массивов.

Допустим, у меня есть некоторый json, который включает ключи dictionnay (dict) и источник json (source).В этом примере я хотел бы выбрать массивы "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: error (at: 26): Невозможно индексировать массив строкой «valueA»

Я также пытался выбрать подходящие объектыон содержит ключи в dict:

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

, но это приводит к ошибке «Невозможно проверить, есть ли у массива ключ объекта»

Надеюсь, я достаточно ясен, чтобы объяснить свои потребности / проблемы.

Любые советы приветствуются.

Ответы [ 3 ]

0 голосов
/ 16 октября 2018

Для простоты давайте начнем с предположения, что основной задачей является получение значений, связанных с одним конкретным ключом.В целях изложения и ясности давайте определим функцию соответственно:

# 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

Вариации

Это решение имеетнесколько потенциальных проблем:

  • Возможно, что один или несколько интересующих ключей вообще не встречаются при вводе;

  • ItВозможно, что одна или несколько интересующих клавиш встречаются более одного раза на входе;

  • Если вход большой, тогда может быть предпочтительнее более эффективное решение.

Первые две проблемы могут быть легко решены, но детали будут зависеть от подробных требований.С проблемой эффективности также можно легко справиться, изменив def getKeyValue так, чтобы названный аргумент был массивом строк.

0 голосов
/ 16 октября 2018

В качестве обучающего опыта (для нас обоих), вот версия, которая напоминает ваш последний пример:

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

, которая начинает наш захват .source как $source, затем повторяется по .dict[], обозначая каждый ключ в нем как $key.Затем он переключается обратно на $source и возвращается к нему (с .., который является более короткой версией recurse(.[]?). Затем select ищет любые подобъекты с ключом с именем $key и следующимКонструктор объекта извлекает эту единственную пару ключ / значение. Наконец, add объединяет все эти объекты в один.

Я не даю никаких обещаний, что это лучше или быстрее, чем другие решения, но это наглядно:)

0 голосов
/ 16 октября 2018

Сделать рекурсивную функцию.Что-то вроде

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

Извините за код sudo!

...