Поскольку вы указали, что хотите обрабатывать «ежедневные» значения отдельно от «ежемесячных» значений, давайте сосредоточимся на первом.
Для этого давайте начнем с использования fromstream
и truncate_stream
:
С вводом, подобным приведенному в примере, но настроенным так, чтобы он действовал в формате JSON:
fromstream( 1|truncate_stream(1|truncate_stream(
inputs | select( .[0][0] == "stats" and .[0][1] == "daily" ) )) )
даст:
{"k1":{"a":[1]},"k2":{"a":[1]},"kN":{"a":[1]}}
Если у вас есть jq 1.6, то приведенный выше фильтр jq можно упростить до:
fromstream(2|truncate_stream(
inputs | select( .[0][0:2] == ["stats","daily"] ) ))
Теперь мы должны использовать atomize
вместо fromstream
для получения желаемого результата. Например, используя jq 1.6, мы видим, что:
atomize(2|truncate_stream(
inputs | select( .[0][0:2] == ["stats","daily"] ) ))
будет производить:
{"k1":{"a":[1]}}
{"k2":{"a":[1]}}
{"kN":{"a":[1]}}
1024 * Воззвание *
jq -n -c --stream -f program.jq input.json
Повышение эффективности
При условии, что объекты на входе не имеют повторяющихся ключей, приведенное выше решение может быть упрощено, так что после обработки интересующего ключа дальнейшая обработка не производится. Это может быть достигнуто с помощью run/3
, как определено ниже. Тогда потоковое решение становится:
atomize( 1 | truncate_stream( 1 | truncate_stream(
run( inputs; .[0][0:2]; ["stats", "daily"] ))))
или с JQ 1.6:
atomize( 2 | truncate_stream(
run( inputs; .[0][0:2]; ["stats", "daily"] )))
run/3
# emit the first run of items in the stream for which f == $value
def run(stream; f; $value):
label $done
| foreach stream as $x ( {};
($x | f) as $k
| if .start then (if $k == $value then . else .stop = true end)
elif $k == $value then .start = true
else .
end;
if .stop then break $done
elif .start then $x
else empty
end );