简体   繁体   中英

jq: translate array of objects to object

I have a response from curl in a format like this:

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

Given a mapping between ids like this:

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

I want to make this:

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

Such that I get a mapping from ids to values (and along the way I'd like to remap the ids).

I've been working at this for a while and every time I get a deadend.

Note: I can use Shell or the like to preform loops if necessary.

edit: Here's one version what I've developed so far:

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

I don't think it's the best one, but I'm looking to see if I can find an old version that was closer to what I need.

[EDIT: The following response was in answer to the question when it described (a) the mapping as shown below, and (b) the input data as having the form:

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

END OF EDIT]

In the following I'll assume that the mapping is available via the following function, but that is an inessential assumption:

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

The following jq filter will then produce the desired output:

map( .list
     |= (map( to_entries[]
              | (mapping[.key]) as $mapped
              | select($mapped)
              | {($mapped|tostring): .value} )
         | add) )

There's plenty of ways to skin a cat. I'd do it like this:

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

You would just provide the mapping through a separate file or argument.

$ 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
    }
  }
]

Here is a reduce-free solution to the revised problem.

In the following I'll assume that the mapping is available via the following function, but that is an inessential assumption:

def mapping:
{
  "12": "newId1",
  "13": "newId2",
  "14": "newId3"
} ;


map( .list
     |= (map( mapping[.id|tostring] as $mapped
              | select($mapped)
              |  {($mapped): .value} )
         | add) )

The "select" is for safety (ie, it checks that the .id under consideration is indeed mapped). It might also be appropriate to ensure that $mapped is a string by writing {($mapped|tostring): .value} .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM