Как можно использовать jq-1.5-1-a5b5cbe, чтобы соединить отфильтрованный набор массивов из STDIN с набором объектов, который не содержит общих полей, предполагая, что все элементы будут в предсказуемом порядке?

Стандартный ввод (pre-slurpfile; генерируется несколькими GET):

{"ref":"objA","arr":["alpha"]}
{"ref":"objB","arr":["bravo"]}

Существующий файл:

[{"name":"foo"},{"name":"bar"}]

Желаемый результат:

[{"name":"foo","arr":["alpha"]},{"name":"bar","arr":["bravo"]}]

Текущий Bash:

$ multiGET | jq --slurpfile stdin /dev/stdin '.[].arr = $stdin[].arr' file
[
  {
    "name": "foo",
    "arr": [
      "alpha"
    ]
  },
  {
    "name": "bar",
    "arr": [
      "alpha"
    ]
  }
]
[
  {
    "name": "foo",
    "arr": [
      "bravo"
    ]
  },
  {
    "name": "bar",
    "arr": [
      "bravo"
    ]
  }
]

Sidenote: Я не был уверен, когда использовать симпатичный / компактный JSON в этом вопросе; Пожалуйста, прокомментируйте свое мнение о наилучшей практике.

2
vintnes 18 Авг 2019 в 11:36

2 ответа

Лучший ответ

Получите jq для чтения file перед стандартным вводом, чтобы первая сущность в file была ., а вы можете получить все остальное, используя inputs.

$ multiGET | jq -c '. as $objects
| [ foreach (inputs | {arr}) as $x (-1; .+1;
    . as $i | $objects[$i] + $x
) ]' file -
[{"name":"foo","arr":["alpha"]},{"name":"bar","arr":["bravo"]}]
2
oguz ismail 19 Авг 2019 в 12:29
  1. «Slurping» (будь то с помощью -s или --slurpfile) иногда необходимо, но редко желательно из-за требований к памяти. Итак, вот решение, которое использует тот факт, что ваш multiGET создает поток:
multiGET | jq -n --argjson objects '[{"name":"foo"},{"name":"bar"}]' '
  $objects
  | [foreach inputs as $in (-1; .+1; 
      . as $ix
      | $objects[$ix] + ($in | del(.ref)))]
'
  1. Вот функциональный подход, который может подойти, если ваш поток уже был упакован в массив:
multiGET | jq -s --argjson objects '[{"name":"foo"},{"name":"bar"}]' '
  [$objects, map(del(.ref))]
  | transpose
  | map(add)
'
  1. Если массив $objects находится в файле или слишком велик для командной строки, я бы предложил использовать --argfile, хотя это технически не рекомендуется.

  2. Если массив $ objects находится в файле, и если вы хотите избежать --argfile, вы все равно можете избежать потери, например используя тот факт, что если не используется -n, jq автоматически прочитает одну сущность JSON из stdin:

(echo '[{"name":"foo"},{"name":"bar"}]';
 multiGET) | jq '
   . as $objects
   | [foreach inputs as $in (-1; .+1;
        . as $ix | $objects[$ix] + $in | del(.ref))] 
'
2
peak 18 Авг 2019 в 11:13