使用jq删除嵌套数组的匹配/不匹配元素

时间:2018-11-27 01:04:35

标签: json jq data-partitioning

我需要将声纳分析历史记录的结果分为单个文件。假设下面有一个起始输入,

    {
  "paging": {
    "pageIndex": 1,
    "pageSize": 100,
    "total": 3
  },
  "measures": [
    {
      "metric": "coverage",
      "history": [
        {
          "date": "2018-11-18T12:37:08+0000",
          "value": "100.0"
        },
        {
          "date": "2018-11-21T12:22:39+0000",
          "value": "100.0"
        },
        {
          "date": "2018-11-21T13:09:02+0000",
          "value": "100.0"
        }
      ]
    },
    {
      "metric": "bugs",
      "history": [
        {
          "date": "2018-11-18T12:37:08+0000",
          "value": "0"
        },
        {
          "date": "2018-11-21T12:22:39+0000",
          "value": "0"
        },
        {
          "date": "2018-11-21T13:09:02+0000",
          "value": "0"
        }
      ]
    },
    {
      "metric": "vulnerabilities",
      "history": [
        {
          "date": "2018-11-18T12:37:08+0000",
          "value": "0"
        },
        {
          "date": "2018-11-21T12:22:39+0000",
          "value": "0"
        },
        {
          "date": "2018-11-21T13:09:02+0000",
          "value": "0"
        }
      ]
    }
  ]
}

如何使用jq清理结果,以便仅保留每个元素的历史记录数组条目?所需的输出是这样的(用于在“ 2018-11-18T12:37:08 + 0000”上完成分析的output-20181118123808.json):

{
  "paging": {
    "pageIndex": 1,
    "pageSize": 100,
    "total": 3
  },
  "measures": [
    {
      "metric": "coverage",
      "history": [
        {
          "date": "2018-11-18T12:37:08+0000",
          "value": "100.0"
        }
      ]
    },
    {
      "metric": "bugs",
      "history": [
        {
          "date": "2018-11-18T12:37:08+0000",
          "value": "0"
        }
      ]
    },
    {
      "metric": "vulnerabilities",
      "history": [
        {
          "date": "2018-11-18T12:37:08+0000",
          "value": "0"
        }
      ]
    }
  ]
}

我迷失了如何仅对子元素进行操作而又不影响父结构的情况。 JSON文件的命名将通过jq实用程序在外部进行处理。提供的样本数据将分为3个文件。其他一些输入可以具有可变数量的条目,有些则可以多达10000个。谢谢。

2 个答案:

答案 0 :(得分:0)

这是一个使用awk编写不同文件的解决方案。该解决方案假定每个度量的日期相同且顺序相同,但对不同日期的数量或独立度量的数量没有限制。

jq -c 'range(0; .measures[0].history|length) as $i
  | (.measures[0].history[$i].date|gsub("[^0-9]";"")),  # basis of filename
    reduce range(0; .measures|length) as $j (.;
      .measures[$j].history |= [.[$i]])' input.json |
awk -F\\t 'fn {print >> fn; fn="";next}{fn="output-" $1 ".json"}'

评论

此处选择awk只是为了方便。

这种方法的缺点是,如果要对每个文件进行整齐的格式化,则每个文件都需要额外运行一次漂亮打印机(例如jq)。因此,如果每个文件中的输出要求整洁,则可以为每个日期运行一次jq,从而省去了后处理(awk)步骤的需要。

如果措施的日期不是固定的,则仍可以使用与上述相同的方法,但是当然,日期的收集和相应措施必须以不同的方式进行。

输出

上面的jq调用产生的前两行如下:

"201811181237080000"
{"paging":{"pageIndex":1,"pageSize":100,"total":3},"measures":[{"metric":"coverage","history":[{"date":"2018-11-18T12:37:08+0000","value":"100.0"}]},{"metric":"bugs","history":[{"date":"2018-11-18T12:37:08+0000","value":"0"}]},{"metric":"vulnerabilities","history":[{"date":"2018-11-18T12:37:08+0000","value":"0"}]}]}

答案 1 :(得分:0)

在评论中,出现了原始问题的以下附录:

  

是否有一个变体,其中过滤是基于日期值而不是位置?无法保证顺序相同或每个度量标准中的元素数量相同(即某些日期可能缺少“错误”,有些日期可能具有其他度量标准,例如“复杂性”)。

以下内容将生成一个JSON对象流,每个日期一个。可以按照我之前的回答用日期对流进行注释,该日期显示了如何使用这些注释来创建各种文件。为了便于理解,我们使用两个辅助函数:

import React, { Component } from "react";

class CSVFileUploader extends Component {

componentDidMount() {

document.getElementById("myBtn").addEventListener("click", () => {

  const reader = new FileReader();
  reader.addEventListener("load", () => {
     document.getElementById("file").innerText = reader.result;
  });
  reader.readAsText(document.querySelector("input").files[0]);
});}

render() {

return (
  <div>
    <input type="file" />
    <button id="myBtn">Read it!</button>
    <pre id="file"></pre>
  </div>
);
}
}

export default CSVFileUploader;

INDEX / 2

如果您的jq没有def dates: INDEX(.measures[].history[].date; .) | keys; def gather($date): map(select(.date==$date)); dates[] as $date | .measures |= map( .history |= gather($date) ) ,则现在是升级的绝佳时机,但是如果这不可行,则其定义如下:

INDEX/2