使用 JQ 创建新对象,其中键来自一个对象,值来自另一个对象

Use JQ to create new object where the key comes from one object and the value comes from another

我有以下输入:

{
  "Columns": [
    {
      "email": 123,
      "name": 456,
      "firstName": 789,
      "lastName": 450,
      "admin": 900,
      "licensedSheetCreator": 617,
      "groupAdmin": 354,
      "resourceViewer": 804,
      "id": 730,
      "status": 523,
      "sheetCount": 298
    }
  ]
}
{
  "Users": [
    {
      "email": "abc@def.com",
      "name": "Abc Def",
      "firstName": "Abc",
      "lastName": "Def",
      "admin": false,
      "licensedSheetCreator": true,
      "groupAdmin": false,
      "resourceViewer": true,
      "id": 521,
      "status": "ACTIVE",
      "sheetCount": 0
    },
    {
      "email": "aaa@bbb.com",
      "name": "Aaa Bob",
      "firstName": "Aaa",
      "lastName": "Bob",
      "admin": false,
      "licensedSheetCreator": true,
      "groupAdmin": false,
      "resourceViewer": false,
      "id": 352,
      "status": "ACTIVE",
      "sheetCount": 0
    }
  ]
}

我需要更改用户中所有键值对的键以匹配列中的值,如下所示:

{
  "Columns": [
    {
      "email": 123,
      "name": 456,
      "firstName": 789,
      "lastName": 450,
      "admin": 900,
      "licensedSheetCreator": 617,
      "groupAdmin": 354,
      "resourceViewer": 804,
      "id": 730,
      "status": 523,
      "sheetCount": 298
    }
  ]
}
{
  "Users": [
    {
      123: "abc@def.com",
      456: "Abc Def",
      789: "Abc",
      450: "Def",
      900: false,
      617: true,
      354: false,
      804: true,
      730: 521,
      523: "ACTIVE",
      298: 0
    },
    {
      123: "aaa@bbb.com",
      456: "Aaa Bob",
      789: "Aaa",
      450: "Bob",
      900: false,
      617: true,
      354: false,
      804: false,
      730: 352,
      523: "ACTIVE",
      298: 0
    }
  ]
}

我不介意更新用户数组或创建新的对象数组。 我尝试了几种组合,包括条目、条目、条目、尝试使用变量搜索键,但我越深入,就越困惑。

流的元素是独立处理的。所以我们必须改变输入。

我们可以将流元素分组到一个数组中。对于输入流,这可以使用 --slurp/-s.[1]

来实现
jq -s '
   ( .[0].Columns[0] | map_values( tostring ) ) as $map |
   (
      .[0],
      (
         .[1:][] |
         .Users[] |= with_entries(
            .key = $map[ .key ]
         )
      )
   )
'

Demo 在 jqplay

或者,我们可以使用 --null-input/-n 结合 input and/or inputs 来读取输入。

jq -n '
   input |
   ( .Columns[0] | map_values( tostring ) ) as $map |
   (
      .,
      (
         inputs |
         .Users[] |= with_entries(
            .key = $map[ .key ]
         )
      )
   )
'

Demo 在 jqplay

请注意,您想要的输出无效 JSON。对象键必须是字符串。所以上面生成的文档与请求的文档略有不同。

请注意,我假设 .Columns 始终是一个只有一个元素的数组。这是一个无意义的假设,但这是问题有意义的唯一方式。


  1. 对于代码生成的流,您可以将流生成器放在数组构造函数中 ([])。 reduce 也可用于从流中收集。例如,map( ... ) 可以写成 [ .[] | ... ]reduce .[] as $_ ( []; . + [ $_ | ... ] ).

以下虽然没有对键进行排序,但具有简单的优点。 它假设 jq 是用 -n 选项调用的,当然会产生一个有效的 JSON 对象流:

input
| . as $Columns
| .Columns[0] as $dict
| input # Users
| .Users[] |= with_entries(.key |= ($dict[.]|tostring))
| $Columns, .

如果对键进行排序很重要,那么您可以轻松地添加合适的代码来做到这一点;或者,如果您不介意对所有对象的键进行排序,则可以使用 -S command-line 选项。