Как обновить отдельное значение в документе json с помощью jq?

107

Прошу прощения, если я пропустил что-то очень очевидное; Я только что нашел jqи пытаюсь использовать его для обновления одного значения JSON, не затрагивая окружающие данные.

Я хотел бы передать curlрезультат jq, обновить значение и передать обновленный JSON в файл curl -X PUT. Что-то вроде

curl http://example.com/shipping.json | jq '.' field: value | curl -X PUT http://example.com/shipping.json

До сих пор я хакнул его вместе с помощью sed, но, посмотрев несколько примеров |=оператора в, jqя уверен, что они мне не нужны.

Вот образец JSON - как мне jqустановить "local": false, сохранив остальную часть JSON?

{
  "shipping": {
    "local": true,
    "us": true,
    "us_rate": {
      "amount": "0.00",
      "currency": "USD",
      "symbol": "$"
    }
  }
}
STW
источник

Ответы:

127

Вы устанавливаете значения объекта с помощью =оператора. |=с другой стороны, используется для обновления значения. Это тонкое, но важное отличие. Контекст фильтров меняется.

Поскольку вы устанавливаете для свойства постоянное значение, используйте =оператор.

.shipping.local = false

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

.shipping.local = false | .shipping.canada = false | .shipping.mexico = true
Джефф Меркадо
источник
10
Этот образец не подходит для нормальной стоимости. Поэтому, если вам нужно изменить нормальное значение, вам нужно добавить "его, например .shipping.local = "new place". Так что вся команда будет curl http://example.com/shipping.json | jq '.shipping.local = "new place"'. В противном случае вы получите странные ошибки.
BMW
8
@BMW что? Здесь все прекрасно. Допустимо любое допустимое значение json, это просто литерал false. Значения не обязательно должны быть строками.
Джефф Меркадо
@BMW OP хочет установить это false. В чем дело?
SOFe
19

Обновите значение (устанавливает .foo.bar на «новое значение»):

jq '.foo.bar = "new value"' file.json

Обновите значение с помощью переменной (устанавливает .foo.bar на "hello"):

variable="hello"; jq --arg variable "$variable" '.foo.bar = $variable' file.json
Пол Крис Джонс
источник
Я использовал это как пример, чтобы переименовать NPM package.json через оболочку, и он работал на 100%, спасибо.
Мачадо
2
Фактически это не заменяет содержимое файла. Он печатает только на стандартный вывод. Вам нужно будет сохранить Stout обратно в файл, чтобы изменения сохранились. См stackoverflow.com/a/60744617/1626687
spuder
2

функция, аналогичная оператору | =, - это map. map будет подходящим, чтобы избежать требования предыдущего фильтра для массива ...

представьте, что ваши данные представляют собой массив (очень часто в этом примере)

[
  {
    "shipping": {
      "local": true,
      "us": true,
      "us_rate": {
        "amount": "1.00",
        "currency": "USD",
        "symbol": "$"
      }
    }
  },
  {
    "shipping": {
      "local": true,
      "us": true,
      "us_rate": {
        "amount": "1.00",
        "currency": "USD",
        "symbol": "$"
      }
    }
  }
]

следовательно, необходимо рассматривать массив в коде как:

http://example.com/shipping.json | jq '.[] | .shipping.local = "new place"' | curl -X PUT http://example.com/shipping.json

или использовать функцию карты, созданную для работы с каждым элементом массива как

http://example.com/shipping.json | jq 'map(.shipping.local = "new place")' | curl -X PUT http://example.com/shipping.json

Наблюдение

Ради тех, кто учится, вы также допустили некоторые ошибки при использовании jq, просто учтите, что он "читает" 1-й параметр как программу, поэтому все желаемые команды должны быть включены в самую первую строку после вызова программа.

Тьяго Конрадо
источник