Удалить совпадающие / несовпадающие элементы вложенного массива с помощью jq - PullRequest
0 голосов
/ 27 ноября 2018

Мне нужно разделить результаты истории анализа сонаркуба на отдельные файлы.Предполагая начальный ввод ниже,

    {
  "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 для очистки результатов, чтобы он сохранял только записи массива истории для каждого элемента?Требуемый вывод выглядит примерно так (output-20181118123808.json для анализа, выполненного на «2018-11-18T12: 37: 08 + 0000»):

{
  "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 голосов
/ 02 декабря 2018

В комментариях появилось следующее дополнение к первоначальному вопросу:

Есть ли вариант, в котором фильтрация основана на значении даты, а не на позиции?Не гарантируется, что порядок будет одинаковым или число элементов в каждой метрике будет одинаковым (то есть в некоторых датах могут отсутствовать «ошибки», в некоторых могут быть дополнительные метрики, такие как «сложность»).

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

def dates:
  INDEX(.measures[].history[].date; .)
  | keys;

def gather($date): map(select(.date==$date));

dates[] as $date
| .measures |= map( .history |= gather($date) )

INDEX / 2

Если ваш jq не имеет INDEX/2, сейчас будет отличное время для обновления, но вЕсли это невозможно, вот его определение:

def INDEX(stream; idx_expr):
  reduce stream as $row ({};
    .[$row|idx_expr|
      if type != "string" then tojson
      else .
      end] |= $row);
0 голосов
/ 27 ноября 2018

Вот решение, которое использует 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"}]}]}
...