Используйте jq для объединения ключей с общим идентификатором - PullRequest
1 голос
/ 14 февраля 2020

рассмотрим файл 'b. json':

[
  {
    "id": 3,
    "foo": "cannot be replaced, id isn't in a.json, stay untouched",
    "baz": "do not touch3"
  },
  {
    "id": 2,
    "foo": "should be replaced with 'foo new2'",
    "baz": "do not touch2"
  }
]

и 'a. json':

[
  {
    "id": 2,
    "foo": "foo new2",
    "baz": "don't care"
  }
]

Я хочу обновить ключ "foo" в б. json с использованием jq с совпадающим значением из. json. Он также должен работать с более чем одной записью в. json.

Таким образом, желаемый вывод:

[
  {
    "id": 3,
    "foo": "cannot be replaced, id isn't in a.json, stay untouched",
    "baz": "do not touch3"
  },
  {
    "id": 2,
    "foo": "foo new2",
    "baz": "do not touch2"
  }
]

Ответы [ 2 ]

1 голос
/ 15 февраля 2020

Вот общий ответ c, который не делает никаких предположений о значениях ключей .id, за исключением того, что они являются различными JSON значениями.

Обобщение INDEX / 2

def type2: [type, if type == "string" then . else tojson end];

def dictionary(stream; f):
  reduce stream as $s ({}; setpath($s|f|type2; $s));

def lookup(value):
  getpath(value|type2);

def indictionary(value):
  (value|type2) as $t
  | has($t[0]) and (.[$t[0]] | has($t[1]));

Invocation

jq --argfile a a.json -f program.jq b.json 

main

dictionary($a[]; .id) as $dict
| b
| map( .id as $id 
       | if ($dict|indictionary($id)) 
         then .foo = ($dict|lookup($id).foo) 
         else . end)
1 голос
/ 15 февраля 2020

Вот одна из нескольких возможностей, которые используют INDEX/2. Если ваш jq не имеет этого в качестве встроенного, см. Ниже.

jq --argfile a a.json '
  INDEX($a[]; .id) as $dict
  | map( (.id|tostring) as $id
         | if ($dict|has($id)) then .foo = $dict[$id].foo 
           else . end)' b.json

Есть и другие способы передать содержимое a. json и b. json.

Предостережение

Приведенное выше использование INDEX предполагает отсутствие "столкновений", которые произошли бы, если, например, один из объектов имеет .id, равный 1, а другой имеет .id, равный на «1». Если существует вероятность такого столкновения, то можно использовать более сложное определение INDEX.

INDEX/2

Прямо от builtin.jq:

def INDEX(stream; idx_expr):
  reduce stream as $row ({}; .[$row|idx_expr|tostring] = $row);
...