Jq: преобразовать массив объектов в объект

user2752635 спросил: 28 марта 2018 в 03:07 в: json

У меня есть ответ от curl в таком формате:

[
  {
    "list": [
      {
        "value": 1,
        "id": 12
      },
      {
        "value": 15,
        "id": 13
      },
      {
        "value": -4,
        "id": 14
      }
    ]
  },
  ...
]

Учитывая сопоставление между идентификаторами вроде:

{
  "12": "newId1",
  "13": "newId2",
  "14": "newId3"
}

Я хочу сделать это:

[
  {
    "list": {
      "newId1": 1,
      "newId2": 15,
      "newId3": -4,
    }
  },
  ...
]

Таким образом, я получаю сопоставление от идентификаторов до значений (и по пути, который я хотел бы переназначить идентификаторы).

Я работал над этим некоторое время, и каждый раз, когда я получаю зависание.

Примечание. Я могу использовать Shell или подобное, чтобы при необходимости создать петли.

edit: Вот одна версия, которую я разработал до сих пор:

jq '[].list.id = ($mapping.[] | select(.id == key)) | del(.id)' -M --argjson "mapping" "$mapping"

Я не думаю, что это лучший, но я смотрю, могу ли я найти старый версия, которая была ближе к тому, что мне нужно.

3 ответа

Есть решение
peak ответил: 30 марта 2018 в 07:10

[РЕДАКТИРОВАТЬ: следующий ответ был в ответ на вопрос, когда он описал (а) отображение, как показано ниже, и (б) входные данные, имеющие форму:

[
  {
    "list": [
      {
        "value": 1,
        "id1": 12
      },
      {
        "value": 15,
        "id2": 13
      },
      {
        "value": -4,
        "id3": 14
      }
    ]
  }
]

КОНЕЦ РЕДАКТИРОВАНИЯ]

В дальнейшем я буду предполагать, что отображение доступно через следующую функцию, но это необязательное предположение:

def mapping: {
  "id1": "newId1",
  "id2": "newId2",
  "id3": "newId3"
} ;

Следующий фильтр jq выдаст желаемый результат:

map( .list
     |= (map( to_entries[]
              | (mapping[.key]) as $mapped
              | select($mapped)
              | {($mapped|tostring): .value} )
         | add) )
user2752635 ответил: 28 марта 2018 в 04:06
В строке 3 не будет ли .key = 0, 1 или 2? Разве это не всегда будет неопределенный индекс в переменной отображения?
user2752635 ответил: 28 марта 2018 в 04:17
Не берите в голову. Я получил это на работу! Большое вам спасибо, я боролся с этим часами.
peak ответил: 30 марта 2018 в 07:11
@ user2752635 - Кто-то изменил вопрос, поэтому я добавил отдельный ответ.
Jeff Mercado ответил: 28 марта 2018 в 02:37

Есть много способов снять кожу с кошки. Я бы сделал это так:

.[].list |= reduce .[] as $i ({};
    ($i.id|tostring) as $k
      | (select($mapping | has($k))[$mapping[$k]] = $i.value) // .
)

Вы бы просто предоставили отображение через отдельный файл или аргумент.

$ cat program.jq
.[].list |= reduce .[] as $i ({};
    ($i.id|tostring) as $k
      | (select($mapping | has($k))[$mapping[$k]] = $i.value) // .
)$ cat mapping.json
{
  "12": "newId1",
  "13": "newId2",
  "14": "newId3"
}$ jq --argfile mapping mapping.json -f program.jq input.json
[
  {
    "list": {
      "newId1": 1,
      "newId2": 15,
      "newId3": -4
    }
  }
]
peak ответил: 30 марта 2018 в 07:08

Вот решение без редуцирования исправленной проблемы.

В дальнейшем я буду предполагать, что отображение доступно через следующую функцию, но это несущественное предположение:

def mapping:
{
  "12": "newId1",
  "13": "newId2",
  "14": "newId3"
} ;map( .list
     |= (map( mapping[.id|tostring] as $mapped
              | select($mapped)
              |  {($mapped): .value} )
         | add) )

"select" предназначен для обеспечения безопасности (т. е. он проверяет, что рассматриваемый .id действительно сопоставлен). Также может быть целесообразным убедиться, что $mapped является строкой, написав {($mapped|tostring): .value}.