Я использую Instana для предоставления статистики просмотров на своем сайте. Каждый ежедневный файл выглядит следующим образом:
{
"items" : [ {
"name" : "page1.htm",
"earliestTimestamp" : 1675222177839,
"cursor" : {
"@class" : ".IngestionOffsetCursor",
"ingestionTime" : 1675292168217,
"offset" : 1
},
"metrics" : {
"uniqueSessions.distinct_count" : [ [ 1675292400000, 4.0 ] ]
}
}, {
"name" : "page2.htm",
"earliestTimestamp" : 1675260035165,
"cursor" : {
"@class" : ".IngestionOffsetCursor",
"ingestionTime" : 1675292168217,
"offset" : 2
},
"metrics" : {
"uniqueSessions.distinct_count" : [ [ 1675292400000, 1.0 ] ]
}
}, {
"name" : "page3.htm",
"earliestTimestamp" : 1675228447118,
"cursor" : {
"@class" : ".IngestionOffsetCursor",
"ingestionTime" : 1675292168217,
"offset" : 3
},
"metrics" : {
"uniqueSessions.distinct_count" : [ [ 1675292400000, 7.0 ] ]
}
} ],
"canLoadMore" : false,
"totalHits" : 12,
"totalRepresentedItemCount" : 12,
"totalRetainedItemCount" : 12,
"adjustedTimeframe" : {
"windowSize" : 86400000,
"to" : 1675292400000
}
}
Эти ежедневные файлы следует объединить в один json после фильтрации необходимой информации:
URL (от имени)
дата (первое значение в «uniqueSessions.distinct_count»)
количество посещений страниц: (второе значение в «uniqueSessions.distinct_count»)
Важно, чтобы это было сделано в CMD, поскольку мне приходится использовать командный файл, поскольку целевому пользователю не разрешено запускать сценарии PowerShell и не иметь доступа к какому-либо другому инструменту CL.
На данный момент мне удалось свести файлы к необходимым элементам данных в виде отдельных объектов JSON, используя: type *.json | jq ".items[] | {url: .name, date: .metrics[][0][0], load: .metrics[][0][1]}"
результат выглядит так:
{
"url": "page1.htm",
"date": 1675292400000,
"load": 4
}
{
"url": "page1.htm",
"date": 1675292400000,
"load": 1
}
{
"url": "page1.htm",
"date": 1675292400000,
"load": 7
}
однако, если я попытаюсь заключить его в квадратные скобки (как предлагают учебники), чтобы получить действительный JSON, я получу один файл с кучей массивов, начинающихся и заканчивающихся там, где они были в исходных файлах.
Я сделал домашнее задание и знаю об этом: объединение нескольких файлов json в один файл json с фильтрами jq на самом деле, я немного поигрался с этим, прежде чем спрашивать. Я подумал, что если бы я мог снова добавить фигурные скобки и корневой узел, это помогло бы, но я не нашел способа, с помощью которого JQ не преминул бы это сделать, отметив, что, скорее всего, ошибка возникает из-за использования кавычек Windows cmd.
Как я могу превратить это в один JSON вместо множества массивов и исходных файлов? Спасибо!
Спасибо, моя проблема в том, что у меня есть несколько файлов JSON. В JQplay мне удалось получить фильтрацию, как в вашем примере, но только для одного файла. Как только я прочитаю все json-файлы, в целевом файле будет столько же массивов, сколько у меня было исходных файлов. Я видел ваш ответ в stackoverflow.com/questions/70302009/… но он также предназначен для фильтрации одних входных данных (внутри одного массива), тогда как у меня будет по одному в день. Или, может быть, я все еще не понимаю, что здесь делает карта?
При наличии нескольких входных данных вам потребуется некоторая структура, охватывающая их все. Либо используйте --slurp, который оборачивает их в массив (в котором вы можете использовать map), либо вызывайте для каждого входа в цикле вышестоящего уровня, например reduce. Я добавил ответ, охватывающий оба.

Для нескольких входных файлов вы можете создать вокруг них еще один массив, используя опцию --slurp (или -s), а затем использовать map:
jq -s 'map(.items[] | {…})' *.json
Или программно выполнить итерацию (например, используя reduce) по каждому вводу (используя inputs в сочетании с флагом --null-input (или -n):
jq -n 'reduce inputs as {$items} ([]; . + [$items[] | {…}])' *.json
Спасибо! Использовал первый, работает как часы. (Извините за поздний ответ, некоторое время отсутствовал.)
Мне жаль. Боюсь, я недостаточно знаю Instana и JQ, чтобы точно понять, что вам нужно... Вы также не показали желаемый конечный выходной файл... Однако я достаточно знаю пакетные файлы!
Чистый пакетный файл ниже обрабатывает все файлы *.json и извлекает «необходимые элементы данных», как показано выше. Это первый шаг к правильному решению, поскольку этот пакетный файл можно изменить любым удобным для вас способом.
@echo off
setlocal
for %%f in (*.json) do (
set "url = "
for /F "tokens=2,3 delims=[:,] " %%a in ('findstr "name uniqueSessions" "%%f"') do (
if not defined url (
echo "url": %%a
set "url=%%a"
) else (
echo "date": %%a
echo "load": %%~Nb
set "url = "
)
)
)
Пример вывода:
"url": "page1.htm"
"date": 1675292400000
"load": 4
"url": "page2.htm"
"date": 1675292400000
"load": 1
"url": "page3.htm"
"date": 1675292400000
"load": 7
"url": "page4.htm"
"date": 1675292400000
"load": 3
"url": "page5.htm"
"date": 1675292400000
"load": 6
"url": "page6.htm"
"date": 1675292400000
"load": 2
Возможно, если вы покажете нам желаемый выходной файл, я смогу завершить решение.
Извините, что вернулся так поздно, некоторое время меня не было на связи. Я добавил это в пакетный файл, но он не дал результатов, которые вы показываете: и «url», и «date» содержат URL-адреса, а «загрузка» остается пустым.
Это странно, потому что я скопировал те же данные, которые вы разместили выше, и использую их в качестве входных данных, поэтому моя программа выдает такие результаты. Вы сделали то же самое? То есть используйте данные, которые вы разместили выше, а не другие, возможно, другие данные...
Добавление |jq -s к тому, что у вас уже есть, должно сработать:
type *.json |
jq ".items[] | {url: .name, date: .metrics[][0][0], load: .metrics[][0][1]}" |
jq -s
Завершающий jq -s может выполнить перенос массива за вас, если у вас есть такой список объектов json:
§ cat input-malformed.json
{ "a" : 1,
"b" : 2 }
{ "a" : 11,
"b" : 22 }
§ cat input-malformed.json | jq -s
[
{
"a": 1,
"b": 2
},
{
"a": 11,
"b": 22
}
]
У меня нет под рукой компьютера с Windows, но работает эквивалент bash в jq версии 1.6 (где a.json и b.json — это копии ваших входных документов JSON):
cat a.json b.json |
jq ".items[] | {url: .name, date: .metrics[][0][0], load: .metrics[][0][1]}" |
jq -s
Также попробовал это (после замены части cat на тип *.json), и это дало тот же результат, что и @pmf (который также включил -s), так что ответ на 100% ПРАВИЛЬНЫЙ, но поскольку (а) он ответил ранее, я принял это. Спасибо за внимание!
Вы хотите использовать
mapвместо.[]для сохранения массива? Демо