Вопрос или проблема
Начнем с примера вывода:
{
"title": "Флэш (2014)",
"alternateTitles": [
{
"title": "Флэш",
"seasonNumber": -1
}
],
"sortTitle": "флэш 2014",
"seasonCount": 7,
"totalEpisodeCount": 154,
"episodeCount": 142,
"episodeFileCount": 0,
"sizeOnDisk": 0,
"status": "продолжается",
"overview": "После удара молнии Барри Аллен просыпается из комы и обнаруживает, что обрёл суперскорость, став Флэшем и сражаясь с преступностью в Центральном городе.",
"nextAiring": "2021-05-19T00:00:00Z",
"previousAiring": "2021-05-12T00:00:00Z",
"network": "The CW",
"airTime": "20:00",
"images": [
{
"coverType": "баннер",
"url": "/MediaCover/37/banner.jpg?lastWrite=637552858236774582",
"remoteUrl": "https://artworks.thetvdb.com/banners/graphical/279121-g7.jpg"
},
{
"coverType": "постер",
"url": "/MediaCover/37/poster.jpg?lastWrite=637552858237654584",
"remoteUrl": "https://artworks.thetvdb.com/banners/posters/279121-5.jpg"
},
{
"coverType": "фанарт",
"url": "/MediaCover/37/fanart.jpg?lastWrite=637552858239814588",
"remoteUrl": "https://artworks.thetvdb.com/banners/fanart/original/279121-9.jpg"
}
],
"seasons": [
{
"seasonNumber": 0,
"monitored": false,
"statistics": {
"episodeFileCount": 0,
"episodeCount": 0,
"totalEpisodeCount": 8,
"sizeOnDisk": 0,
"percentOfEpisodes": 0
}
},
{
"seasonNumber": 1,
"monitored": true,
"statistics": {
"previousAiring": "2015-05-20T00:00:00Z",
"episodeFileCount": 0,
"episodeCount": 0,
"totalEpisodeCount": 23,
"sizeOnDisk": 0,
"percentOfEpisodes": 0
}
},
{
"seasonNumber": 2,
"monitored": true,
"statistics": {
"previousAiring": "2016-05-25T00:00:00Z",
"episodeFileCount": 0,
"episodeCount": 0,
"totalEpisodeCount": 23,
"sizeOnDisk": 0,
"percentOfEpisodes": 0
}
},
{
"seasonNumber": 3,
"monitored": true,
"statistics": {
"previousAiring": "2017-05-24T00:00:00Z",
"episodeFileCount": 0,
"episodeCount": 0,
"totalEpisodeCount": 23,
"sizeOnDisk": 0,
"percentOfEpisodes": 0
}
},
{
"seasonNumber": 4,
"monitored": true,
"statistics": {
"previousAiring": "2018-05-23T00:00:00Z",
"episodeFileCount": 0,
"episodeCount": 0,
"totalEpisodeCount": 23,
"sizeOnDisk": 0,
"percentOfEpisodes": 0
}
},
{
"seasonNumber": 5,
"monitored": true,
"statistics": {
"previousAiring": "2019-05-15T00:00:00Z",
"episodeFileCount": 0,
"episodeCount": 0,
"totalEpisodeCount": 22,
"sizeOnDisk": 0,
"percentOfEpisodes": 0
}
},
{
"seasonNumber": 6,
"monitored": true,
"statistics": {
"previousAiring": "2020-05-13T00:00:00Z",
"episodeFileCount": 0,
"episodeCount": 0,
"totalEpisodeCount": 19,
"sizeOnDisk": 0,
"percentOfEpisodes": 0
}
},
{
"seasonNumber": 7,
"monitored": true,
"statistics": {
"nextAiring": "2021-05-19T00:00:00Z",
"previousAiring": "2021-05-12T00:00:00Z",
"episodeFileCount": 0,
"episodeCount": 0,
"totalEpisodeCount": 13,
"sizeOnDisk": 0,
"percentOfEpisodes": 0
}
}
],
"year": 2014,
"path": "/home/cas/plex-media/series/Флэш (2014)",
"profileId": 6,
"languageProfileId": 1,
"seasonFolder": true,
"monitored": false,
"useSceneNumbering": false,
"runtime": 42,
"tvdbId": 279121,
"tvRageId": 36939,
"tvMazeId": 13,
"firstAired": "2014-10-07T00:00:00Z",
"lastInfoSync": "2021-05-16T03:08:01.309493Z",
"seriesType": "standard",
"cleanTitle": "флэш2014",
"imdbId": "tt3107288",
"titleSlug": "флэш-2014",
"certification": "TV-PG",
"genres": [
"Экшн",
"Приключения",
"Драма",
"Научная Фантастика"
],
"tags": [],
"added": "2021-04-29T09:37:02.970046Z",
"ratings": {
"votes": 6551,
"value": 8.7
},
"qualityProfileId": 6,
"id": 37
}
Теперь я хочу изменить значение .seasons | .[] | select(.seasonNumber==2).monitored
на false. Я смог сделать это с помощью следующего:
# '.[] | select(.title==$TITLE)' используется для получения примера вывода
# '--argjson SEASON "$((season-1))"' будет 2 в этом случае (возвращая 3-й объект, который действительно является 2-м сезоном)
[api request] | jq -rM --arg TITLE "${info[$((series-1))]}" --arg SEASON "$((season-1))" '.[] | select(.title==$TITLE).seasons | .[] | select(.seasonNumber==$SEASON) | .monitored = false'
{
"seasonNumber": 2,
"monitored": false,
"statistics": {
"previousAiring": "2016-05-25T00:00:00Z",
"episodeFileCount": 0,
"episodeCount": 0,
"totalEpisodeCount": 23,
"sizeOnDisk": 0,
"percentOfEpisodes": 0
}
}
Однако я не хочу этот вывод. Я теперь получаю только сам объект. Я хочу получить полный пример вывода с изменённым значением. Я думаю, что проблемы в |
после .seasons
, но не знаю, как это исправить.
Моя цель – получить пример вывода, но с изменённым на false
(и только для сезона, который я хочу)
ДОПОЛНЕНИЕ: следовало упомянуть, что я хочу получить вывод непосредственно в терминале и корректно. То есть не сохранять в файл в конце или в середине процесса (а затем использовать это в новой команде). Несколько команд и переменных допустимы.
ОТВЕТ МУРУ:
# для простоты я изменил значения --arg'ов на фактические значения
jq --arg TITLE "Флэш (2014)" --arg SEASON "2" '.[] | select(.title==$TITLE).seasons[] |= (select(.seasonNumber==$SEASON) |= (.monitored = false))'
Прежде всего, выводится [api request]
вместо [api request] | jq -rM --arg TITLE "Флэш (2014)" '.[] | select(.title==$TITLE)'
Во-вторых, это… не меняет значение. Игнорируя полный вывод API, вместо этого он по-прежнему показывает "monitored": true,
для "seasonNumber": 2,
.
ДОПОЛНЕНИЕ2:
Я это сделал:
jq --arg TITLE "Флэш (2014)" --argjson SEASON "4" '.[] | select(.title==$TITLE) | .seasons[] |= (select(.seasonNumber==$SEASON) |= (.monitored = false))'
Разница:
select(.title==$TITLE).seasons[]
->select(.title==$TITLE) | .seasons[]
--arg SEASON "4"
->--argjson SEASON "4"
То, что вам нужно, по сути, это два обновления (обновить соответствующий объект сезона, а затем обновить массив сезонов с этим объектом). Итак:
.[] | select(.title==$TITLE).seasons[] |= (select(.seasonNumber==$SEASON) |= (.monitored = false))
Здесь внутреннее обновление (|=
) обновляет select
ированный сезон в исходном массиве, а внешнее |=
обновляет массив результатом.
Ответ или решение
Чтобы изменить значение в JSON с использованием инструмента jq
, особенно когда путь к ключу доступен только через select()
, необходимо учесть несколько вещей. Рассмотрим, как можно изменить значение ключа .monitored
у сезона 2 сериалa "The Flash (2014)" и при этом вернуть полностью обновленный объект JSON.
Исходный JSON содержит массив сезонов, где каждый сезон представлен объектом. Мы хотим изменить значение ключа monitored
для сезона с seasonNumber
равным 2.
Вот общее решение:
jq --arg TITLE "The Flash (2014)" --argjson SEASON 2 \
'(.[] | select(.title==$TITLE).seasons[] | select(.seasonNumber==$SEASON).monitored) = false'
Разбор команды:
--arg TITLE "The Flash (2014)"
– мы задаем переменную, чтобы выбрать нужный сериал по его названию.--argjson SEASON 2
– здесь мы задаем номер сезона, который хотим обновить. Используется--argjson
, поскольку мы передаем числовое значение.(.[] | select(.title==$TITLE).seasons[] | select(.seasonNumber==$SEASON).monitored) = false
– эта часть команды выполняет следующие действия:- Выбирает сериал по заголовку.
- Достает массив сезонов.
- Среди сезонов выбирает сезон с нужным номером.
- Меняет значение
monitored
наfalse
.
После выполнения этой команды мы получим полностью обновленный объект исходного JSON с измененным значением для ключа monitored
для указанного сезона.
Пример использования
Предположим, что вы получили данные из API и сохранили их в переменной api_response
. Тогда вы можете применить jq
следующим образом:
echo "$api_response" | jq --arg TITLE "The Flash (2014)" --argjson SEASON 2 '(.[] | select(.title==$TITLE).seasons[] | select(.seasonNumber==$SEASON).monitored) = false'
Этот вызов выведет обновленный JSON, содержащий все данные, в том числе изменения, которые вы внесли.
Заключение
Таким образом, используя jq
, можно легко обновлять значения в JSON-структурах, применяя фильтры select()
для выборки нужных элементов. Это позволяет эффективно обновлять сложные структуры данных, не теряя при этом целостности оригинального JSON.