Добавить JSON Объект в указанное c местоположение - PullRequest
0 голосов
/ 07 января 2020

Вот мои два json содержимого файла:

file1. json

{
  "nodes": [
    {
      "pm_addr": "192.100.0.4",
      "name": "TB1-OSC-A"
    },
    {
      "pm_addr": "192.100.0.6",
      "name": "TB1-OSC-B"
    },
    {
      "pm_addr": "192.100.0.7",
      "name": "TB1-OSC-C"
    }
  ]
}

file2. json

{
  "nodes": [
    {
      "pm_addr": "192.100.0.4",
      "name": "TB1-OSC-D"
    }
  ]
}

Я хочу добавьте содержимое файла 2.. 1022 * в файл 1.. json, но после объекта json: TB1-OS C -B , то есть вторая запись json. В этом случае запись присутствует во втором местоположении, но она может присутствовать в любом другом месте. Мой окончательный файл json должен выглядеть так:

file3. json

{
  "nodes": [
    {
      "pm_addr": "192.100.0.4",
      "name": "TB1-OSC-A"
    },
    {
      "pm_addr": "192.100.0.6",
      "name": "TB1-OSC-B"
    },
    {
      "pm_addr": "192.100.0.4",
      "name": "TB1-OSC-D"
    },
    {
      "pm_addr": "192.100.0.7",
      "name": "TB1-OSC-C"
    }
  ]
}

Я использую версию jq: 1.3, и у меня нет возможности ее обновить. Я пытался использовать параметры add и = +, предоставленные jq. Но это не помогло.

Спасибо в advnace

Ответы [ 2 ]

2 голосов
/ 09 января 2020

Ключом к ясному и понятному решению является наличие подходящих утилит.

Функции утилит для jq 1.3

def insert_at(i; x): .[:i] + [x] + .[i:];

def indicesof(f):
  . as $in
  | range(0;length) | select( $in[.] | f );

def insert_after(f; x):
  [indicesof(f)] as $ix
  | if ($ix|length) > 0
    then insert_at($ix[0]+1; x) 
    else . end;

Функции утилит для jq 1.4 или более поздних версий

jq 1.4 обеспечивает более эффективное решение, благодаря first/1:

def insert_at($i; $x): .[:$i] + [$x] + .[$i:];

def indicesof(f):
  . as $in
  | range(0;length) | select( $in[.] | f );

def insert_after(f; $x):
  (first(indicesof(f)) // null) as $i
  | if $i then insert_at($i + 1; $x) else . end;

Решение

С помощью этих служебных функций решения данной проблемы могут быть выражены напрямую. Например, предполагая вызов по линии:

jq -s -f merge.jq file1.json file2.json

.[1].nodes[0] as $file2
| .[0]
| .nodes |= insert_after(.name == "TB1-OSC-B"; $file2)

Это можно легко изменить в зависимости от подробных требований.

2 голосов
/ 07 января 2020

Если вы хотите добавить объект из file2.json в массив nodes, это довольно просто:

jq -s '.[0].nodes += [ .[1].nodes[0] ] | .[0]' file1.json file2.json

Вывод:

{
  "nodes": [
    {
      "pm_addr": "192.100.0.4",
      "name": "TB1-OSC-A"
    },
    {
      "pm_addr": "192.100.0.6",
      "name": "TB1-OSC-B"
    },
    {
      "pm_addr": "192.100.0.7",
      "name": "TB1-OSC-C"
    },
    {
      "pm_addr": "192.100.0.4",
      "name": "TB1-OSC-D"
    }
  ]
}

Однако, потому что вы хотите чтобы вставить объект, он становится более сложным, поскольку jq AFAIK не поддерживает вставку в массивы, только добавляя и добавляя.

Ниже приведен довольно запутанный пример того, как это сделать, сращив его в:

parse.jq

# Find the desired index and store it as $n
(.[0].nodes | map(.name == "TB1-OSC-B") | index(true)) as $n   |

# Splice the object from the second file  into the first
.[0].nodes =   .[0].nodes[0:($n|tonumber+1)]   +
             [ .[1].nodes[0] ]                 +
               .[0].nodes[($n|tonumber+1):(.[0].nodes|length)] |

# Only output the now modified object from the first file 
.[0]

Запустите его так:

jq -sf parse.jq file1.json file2.json

Вывод в этом случае:

{
  "nodes": [
    {
      "pm_addr": "192.100.0.4",
      "name": "TB1-OSC-A"
    },
    {
      "pm_addr": "192.100.0.6",
      "name": "TB1-OSC-B"
    },
    {
      "pm_addr": "192.100.0.4",
      "name": "TB1-OSC-D"
    },
    {
      "pm_addr": "192.100.0.7",
      "name": "TB1-OSC-C"
    }
  ]
}
...