使用jq向现有的JSON数组添加新元素

118

我想使用 jq``add 命令将元素附加到JSON文件中的数组中,但它不起作用。

report-2017-01-07.json 文件:

{  
   "report": "1.0",
   "data": {  
      "date": "2010-01-07",
      "messages": [  
         {  
            "date": "2010-01-07T19:58:42.949Z",
            "xml": "xml_samplesheet_2017_01_07_run_09.xml",
            "status": "OK",
            "message": "metadata loaded into iRODS successfully"
         },
         {  
            "date": "2010-01-07T20:22:46.949Z",
            "xml": "xml_samplesheet_2017_01_07_run_09.xml",
            "status": "NOK",
            "message": "metadata duplicated into iRODS"
         },
         {  
            "date": "2010-01-07T22:11:55.949Z",
            "xml": "xml_samplesheet_2017_01_07_run_09.xml",
            "status": "NOK",
            "message": "metadata was not validated by XSD schema"
         }
      ]
   }
}

我正在使用这个命令:

$ cat report-2017-01-07.json 
| jq -s '.data.messages {"date": "2010-01-07T19:55:99.999Z", "xml": "xml_samplesheet_2017_01_07_run_09.xml", "status": "OKKK", "message": "metadata loaded into iRODS successfullyyyyy"}'
jq: error: syntax error, unexpected '{', expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
.data.messages {"date": "2010-01-07T19:55:99.999Z", "xml": "xml_samplesheet_2017_01_07_run_09.xml", "status": "OKKK", "message": "metadata loaded into iRODS successfullyyyyy"}               
jq: 1 compile error

这是我希望输出结果的样子:

{
    "report": "1.0",
    "data": {
        "date": "2010-01-07",
        "messages": [{
            "date": "2010-01-07T19:58:42.949Z",
            "xml": "xml_samplesheet_2017_01_07_run_09.xml",
            "status": "OK",
            "message": "metadata loaded into iRODS successfully"
        }, {
            "date": "2010-01-07T20:22:46.949Z",
            "xml": "xml_samplesheet_2017_01_07_run_09.xml",
            "status": "NOK",
            "message": "metadata duplicated into iRODS"
        }, {
            "date": "2010-01-07T22:11:55.949Z",
            "xml": "xml_samplesheet_2017_01_07_run_09.xml",
            "status": "NOK",
            "message": "metadata was not validated by XSD schema"
        }, {
            "date": "2010-01-07T19:55:99.999Z",
            "xml": "xml_samplesheet_2017_01_07_run_09.xml",
            "status": "OKKKKKKK",
            "message": "metadata loaded into iRODS successfullyyyyy"
        }]
    }
}

不太清楚,但是.data.messages不是一个数组吗?所以你需要像.data.messages.[]这样的东西。 - Vanquished Wombat
抱歉,没有生效。 - Felipe
好的 - 阅读了文档并安装了 jq(我这里使用的是 Windows),尝试了一下 - 得到了与您相同的错误。看起来 Windows shell 在将双引号输入流中时存在问题,这会使 jq 出现问题。无法让任何东西正常工作,因此无法回答您的问题,但您可能需要查看如何转义 jq 命令中的双引号。所以 "date" 将变成 \"date\" 等等。 - Vanquished Wombat
如果我使用这个命令,我可以更新所有日期属性。jq '.data.messages[].date = "2010-01-07T99:99:99.999Z"' report-2017-01-07.json 但我还不能添加。 - Felipe
我更新了输出。 - Felipe
3个回答

173

筛选器中的|= .+ 部分会将一个新元素添加到现有数组中。您可以像以下这样使用带有筛选器的jq

jq '.data.messages[3] |= . + {
      "date": "2010-01-07T19:55:99.999Z", 
      "xml": "xml_samplesheet_2017_01_07_run_09.xml", 
      "status": "OKKK", 
      "message": "metadata loaded into iRODS successfullyyyyy"
}' inputJson

为了避免使用硬编码的长度值3并动态添加新元素,请使用. | length,它返回长度,可以用作下一个数组索引,即:
jq '.data.messages[.data.messages| length] |= . + {
      "date": "2010-01-07T19:55:99.999Z", 
      "xml": "xml_samplesheet_2017_01_07_run_09.xml", 
      "status": "OKKK", 
      "message": "metadata loaded into iRODS successfullyyyyy"
}' inputJson

或者按照评论中Peak的建议,仅使用+=运算符

jq '.data.messages += [{
     "date": "2010-01-07T19:55:99.999Z",
     "xml": "xml_samplesheet_2017_01_07_run_09.xml", 
     "status": "OKKK", 
     "message": "metadata loaded into iRODS successfullyyyyy"
}]'

这会生成你所需的输出:

{
  "report": "1.0",
  "data": {
    "date": "2010-01-07",
    "messages": [
      {
        "date": "2010-01-07T19:58:42.949Z",
        "xml": "xml_samplesheet_2017_01_07_run_09.xml",
        "status": "OK",
        "message": "metadata loaded into iRODS successfully"
      },
      {
        "date": "2010-01-07T20:22:46.949Z",
        "xml": "xml_samplesheet_2017_01_07_run_09.xml",
        "status": "NOK",
        "message": "metadata duplicated into iRODS"
      },
      {
        "date": "2010-01-07T22:11:55.949Z",
        "xml": "xml_samplesheet_2017_01_07_run_09.xml",
        "status": "NOK",
        "message": "metadata was not validated by XSD schema"
      },
      {
        "date": "2010-01-07T19:55:99.999Z",
        "xml": "xml_samplesheet_2017_01_07_run_09.xml",
        "status": "OKKK",
        "message": "metadata loaded into iRODS successfullyyyyy"
      }
    ]
  }
}

使用jq-play可以模拟运行您的jq-filter并根据需要进行优化。

6
由于目的只是添加一个元素,使用 += 会更好,但需要注意的是,这里.data.messages[3] |= . + X可以简化为.data.messages[3] = X,因为 RHS 上的.实际上只是null - peak
1
(Windows JQ用户)我想知道是否有可能将这些新数据写入同一个(输入)文件,而不是创建一个需要在之后重命名的临时文件。 - script'n'code
1
@script'n'code - 如果您有sponge或可以安装它(它是moreutils的一部分),那么使用它可能仍然是最好的选择。 - peak
@peak 怎么将那个对象插入到数组的开头,我没想明白。谢谢。 - Nic Huang
@ peak 我如何在向数组插入元素时指定顺序? - Harry Ma

71

不要使用|=,考虑使用+=:

.data.messages += [{"date": "2010-01-07T19:55:99.999Z",
   "xml": "xml_samplesheet_2017_01_07_run_09.xml",
   "status": "OKKK", "message": "metadata loaded into iRODS successfullyyyyy"}]

在前面添加

另一方面,如果你想将JSON对象添加到数组的开头,你可以使用以下方式:

 .data.messages |= [ _ ] + .

4
在编程中进行翻译: 在前面添加示例:echo '{" arr ":[" data1 "]}'|jq'.arr | = ["data2"] +.'=>{" arr ":["data2","data1"]} - Vitalii Zinchenko

49

简述:". + "是你的救星

详细说明:

添加列表项目:您可以追加[list1] + [list2](而不是[list] +数据)

$ echo '[ "data1" ]' | jq '. + [ "data2" ]'
[
  "data1",
  "data2"
]

$ echo '[ {"key1": "value1"} ]' | jq '. + [{"key2": "value2"}]'
[
  {
    "key1": "value1"
  },
  {
    "key2": "value2"
  }
]

向字典中添加键值对:

$ echo '{"key1": "value1"}' | jq '. + {"key2": "value2"}'
{
  "key1": "value1",
  "key2": "value2"
}

参考文献:

https://gist.github.com/joar/776b7d176196592ed5d8


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接