Как выбрать максимальное значение по условию, а затем сравнить его с другими?

#json #max #jq

#json #макс #jq

Вопрос:

У меня есть набор резервных копий, который описывается json. Пример приведен ниже. Я хочу подсчитать, сколько резервных копий было добавлено с момента последнего полного резервного копирования. Я пытаюсь выбрать максимальную временную метку записи с типом «full», поэтому после этого я посчитаю, сколько записей с типом «incr» имеет большую временную метку.

 {
  "archive": [
    {
      "database": {
        "id": 1
      },
      "id": "11-1",
      "max": "0000000A000018B90000006A",
      "min": "0000000A0000167D000000C7"
    }
  ],
  "backup": [
    {
      "archive": {
        "start": "0000000A0000181600000030",
        "stop": "0000000A0000181C00000083"
      },
      "backrest": {
        "format": 5,
        "version": "2.28"
      },
      "database": {
        "id": 1
      },
      "info": {
        "delta": 417875448942,
        "repository": {
          "delta": 67466720725,
          "size": 67466720725
        },
        "size": 417875448942
      },
      "label": "20201213-200009F",
      "prior": null,
      "reference": null,
      "timestamp": {
        "start": 1607878809,
        "stop": 1607896232
      },
      "type": "full"
    },
    {
      "archive": {
        "start": "0000000A0000182900000065",
        "stop": "0000000A0000182F00000069"
      },
      "backrest": {
        "format": 5,
        "version": "2.28"
      },
      "database": {
        "id": 1
      },
      "info": {
        "delta": 122520170241,
        "repository": {
          "delta": 19316550760,
          "size": 67786280115
        },
        "size": 416998156028
      },
      "label": "20201213-200009F_20201214-200009I",
      "prior": "20201213-200009F",
      "reference": [
        "20201213-200009F"
      ],
      "timestamp": {
        "start": 1607965209,
        "stop": 1607974161
      },
      "type": "incr"
    },
    {
      "archive": {
        "start": "0000000A0000185B000000DD",
        "stop": "0000000A0000185B000000F4"
      },
      "backrest": {
        "format": 5,
        "version": "2.28"
      },
      "database": {
        "id": 1
      },
      "info": {
        "delta": 126982395984,
        "repository": {
          "delta": 19541379733,
          "size": 67993072945
        },
        "size": 421395153101
      },
      "label": "20201213-200009F_20201217-200105I",
      "prior": "20201213-200009F_20201214-200009I",
      "reference": [
        "20201213-200009F",
        "20201213-200009F_20201214-200009I"
      ],
      "timestamp": {
        "start": 1608224465,
        "stop": 1608233408
      },
      "type": "incr"
    }
  ]
}
 

Я попытался завершить первую часть этой командой, но в ней говорится, что «число (1607896232) и число (1607896232) не могут быть повторены»

 .[0] |.backup[] | select(.type=="full").timestamp.stop|max
 

Я пробовал sort_by, но безуспешно. Итак, что я здесь делаю не так?

Ответ №1:

С помощью общей вспомогательной функции для подсчета, вот полное решение, предполагая, что вы хотите считать на основе .timestamp.start :

 def count(s): reduce s as $x (0; . 1);

.backup
| (map( select( .type == "full" ).timestamp.stop) | max) as $max
| count(.[] | select( .type == "incr" and  .timestamp.start > $max))
 

Используя max/1

Для больших массивов, вероятно, было бы более эффективно использовать потоковую версию max :

 def count(s): reduce s as $x (0; . 1);

# Note: max(empty) #=> null
def max(s):
  reduce s as $s (null; if $s > .m then $s else . end);

.backup
| max(.[] | select( .type == "full" ).timestamp.stop) as $max
| count(.[] | select( .type == "incr" and  .timestamp.start > $max))
 

Ответ №2:

max ожидает массив.

 [ .backup[] | select( .type == "full" ).timestamp.stop ] | max
 

Тест

или

 .backup | map( select( .type == "full" ).timestamp.stop ) | max
 

Тест

Ответ №3:

Итак, после того, как я решил проблему с получением конкретного значения (спасибо @ikegami), я решил весь свой вопрос таким образом

  jq '(.[0] |[.backup[] | select(.type=="full").timestamp.stop]|max) as $i| [.[0] |.backup[] | select(.type=="incr" and .timestamp.stop>$i)]|length
 

Не уверен, что это оптимально, но все равно работает.

Ответ №4:

Вот также альтернативное (не jq) решение, как добиться того же запроса JSON с jtc помощью tool:

 bash $ <input.json jtc -jw'[timestamp]:<>G:[-1][type]' / -w'<full><>k'
2
 

PS. Я разработчик jtc PPS процессора unix JSON
. вышеуказанный отказ от ответственности требуется SO.