jsonオブジェクトにキー/値を追加/変更する

jsonオブジェクトにキー/値を追加/変更する

私は尋ねたエマルジョンただし、この問題に対する解決策を適用する際に問題があります。

次のjson配列があります。

$ jq <<<"$json"
[
  {
    "id": "node1"
  },
  {
    "id": "node2"
  },
  {
    "id": "node3"
  }
]

各ノードにキー/値を追加するか、すでに存在する場合は変更したいと思います。私はこれを行うことができます:

$ jq '.[] | select(.id == "node2") += {status: "fail"}' <<<"$json"
{
  "id": "node1"
}
{
  "id": "node2",
  "status": "fail"
}
{
  "id": "node3"
}

ただし、外部配列が消えるので、このソリューションをスクリプトで実装しようとすると失敗します。

#!/usr/bin/env bash

[[ $DEBUG == true ]] && set -x

nodes=(node1 node2 node3)
json='[{"id": "node1"},{"id": "node2"},{"id": "node3"}]'

for node in "${nodes[@]}"; do
    if [[ $node == node2 ]]; then
        status=fail
    else
        status=pass
    fi
    json=$(jq --arg status "$status" --arg node "$node" '.[] | select(.id == $node) += {status: $status}' <<<"$json")
done

間違い:

$ ./script.sh
jq: error (at <stdin>:4): Cannot index string with string "id"
jq: error (at <stdin>:7): Cannot index string with string "id"
jq: error (at <stdin>:10): Cannot index string with string "id"

構造全体を維持しながらこれらのjsonオブジェクトを変更する方法はありますか?

答え1

.[]で要素を選択すると、select()それが残った唯一のデータであり、最後に出力される内容です。

代わりに、次map()を使用して、最上位配列の各要素に(可能な)修正を適用します。

$ jq --arg id node2 --arg status fail 'map(select(.id == $id) += { status: $status } )' file
[
  {
    "id": "node1"
  },
  {
    "id": "node2",
    "status": "fail"
  },
  {
    "id": "node3"
  }
]

または、括弧の数が少なく、よりきれいになる可能性があります。

$ jq --arg id node2 --arg status fail 'map(select(.id == $id).status = $status)' file
[
  {
    "id": "node1"
  },
  {
    "id": "node2",
    "status": "fail"
  },
  {
    "id": "node3"
  }
]

jq複数の呼び出しを避けるためにシェルループをコピーしてくださいjq

$ jq --arg failnode node2 'map(.status = if .id == $failnode then "fail" else "pass" end)' file
[
  {
    "id": "node1",
    "status": "pass"
  },
  {
    "id": "node2",
    "status": "fail"
  },
  {
    "id": "node3",
    "status": "pass"
  }
]

--argsまたは、複数のノードに障害が発生し、障害が発生した各ノードをコマンドラインにリストします(通常ではありませんが、最後に必要な配置に注意してください)。

$ jq 'map(.status = if (.id|IN($ARGS.positional[])) then "fail" else "pass" end)' file --args node1 node2
[
  {
    "id": "node1",
    "status": "fail"
  },
  {
    "id": "node2",
    "status": "fail"
  },
  {
    "id": "node3",
    "status": "pass"
  }
]

関連情報