jq: translate array of objects to object

微笑、不失礼 提交于 2019-12-14 01:51:58

问题


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.


回答1:


[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) )



回答2:


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



回答3:


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 (i.e., 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}.



来源:https://stackoverflow.com/questions/49958035/jq-translate-array-of-objects-to-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!