【问题标题】:Adding new JSON fields using jq when value not matched当值不匹配时使用 jq 添加新的 JSON 字段
【发布时间】:2021-09-27 15:32:11
【问题描述】:

我有以下示例 json

{
  "environment": [
        {
      "name": "user1",
      "value": "app"
    },
            {
      "name": "user2",
      "value": "admin"
    },
    {
      "name": "user3",
      "value": "db"
    }


  ]
}

当名称存在时,我需要用新值(作为输入参数传递给脚本)更新值。如果给出了不同的名称和值,则需要在最后附加它们作为新字段。 例如,如果 name=user4 和 value=root 那么我的新 json 应该是这样的

{
  "environment": [
        {
      "name": "user1",
      "value": "app"
    },
            {
      "name": "user2",
      "value": "admin"
    },
    {
      "name": "user3",
      "value": "db"
    },
    {
      "name": "user4",
      "value": "root"
    }

  ]
}

如果现有值作为 user3,aws 给出,那么它必须更新 user3 的值,如下所示

{
  "environment": [
        {
      "name": "user1",
      "value": "app"
    },
            {
      "name": "user2",
      "value": "admin"
    },
    {
      "name": "user3",
      "value": "aws"
    }


  ]
}

它按预期工作,但只有以下问题。 当我的 JSON 在环境标签之前有任何额外的标签时,在执行命令后,这些标签会被修剪掉,下次当我使用不同的输入运行相同的命令时,它不会找到以前的现有标签并给出此错误 Cannot iterate over null (null) 使用 peak 给出的以下命令,taskDefinition 和 containerDefinitions 标签正在被修剪掉。因此,请帮助我将这些标签放在适当的位置。

 jq  --arg updateName "user5" --arg updateVal "admin" '
  .taskDefinition | .containerDefinitions[] | .environment |=
       if any(.[]; .name == $updateName)
       then map(if .name == $updateName then .value = $updateVal else . end)
       else (. + [{"name": $updateName, "value": $updateVal}] )
       end' envt_values1.json
{
    "taskDefinition": {
        "containerDefinitions": [
            {
              "environment": [
                {
                  "name": "user1",
                  "value": "app"
                },
                {
                  "name": "user2",
                  "value": "admin"
                },
                {
                  "name": "user3",
                  "value": "aws"
                },
                {
                  "name": "user4",
                  "value": "root"
                },
                {}
              ],
              "configuration": []
            }
        ]
    }
}

【问题讨论】:

    标签: json jq


    【解决方案1】:

    这实现了我理解的要求:

    jq  --arg updateName "user4" --arg updateVal "root" '
      .environment |= 
           if any(.[]; .name == $updateName)
           then map(if .name == $updateName then .value = $updateVal else . end)
           else (. + [{"name": $updateName, "value": $updateVal}] )
           end' input.json
           
    

    【讨论】:

    • 感谢您快速更新解决方案。它正在工作,但我对 json 中的空值有另一个问题。由于它给出了这个错误“不能迭代null(null)”。和最新的json如下。请帮忙
    • { "taskDefinition": { "containerDefinitions": [ { "environment": [ { "name": "user1", "value": "app" }, { "name": "user2 ", "value": "admin" }, { "name": "user3", "value": "aws" }, { "name": "user4", "value": "root" }, {} ] , "配置": [] } ] } }
    • 请忽略我上面的 cmets 并检查问题部分的最新更新
    【解决方案2】:

    你关心要修改的数组中元素的顺序吗?

    不,数组是无序的

    获取一个仅包含那些不匹配的元素的数组 (map(select(.name != $name))),并无条件地向其中添加一个包含新数据的元素 (+ [{$name,$value}])。这样,当且仅当现有元素匹配时,它才会被删除,并且在任何情况下都会添加一个新元素。添加(或更新)的将始终位于数组的最终位置,而不是任何“删除位置”。

    jq --arg name "user4" --arg value "root"  '
      
      .environment |= map(select(.name != $name)) + [{$name,$value}]
    
    ' envt.json
    

    是的,数组是有序的

    如果数组是有序的,则只应在数组末尾添加一个真正的新元素,而更新的元素应在数组中的原始位置替换。

    为此,我们不会像以前那样更新整个数组 (.environment |= …),只更新某些重要的元素 ((.environment | …) |= …)。如果有匹配条件的元素 ((.[] | select(.name == $name))),它们很重要,否则 (//) 位置处的元素 length(超过数组的末尾,因此是新的,因为索引从 0 变为仅 @ 987654330@) 是最重要的。无论哪个元素通过,它们都将使用提供的数据进行更新 (|= {$name,$value}):

    jq --arg name "user4" --arg value "root"  '
      
      (.environment | ((.[] | select(.name == $name)) // .[length])) |= {$name,$value}
    
    ' envt.json
    

    旁注:我还将输入变量重命名为$name$value(根据未来的字段名称),以简化将新对象创建为{$name,$value}

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-19
      • 1970-01-01
      • 2017-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-05
      相关资源
      最近更新 更多