Преобразование сложного файла JSON в простой файл JSON с использованием JQ без получения декартового произведения - PullRequest
0 голосов
/ 02 июля 2018

Я хочу преобразовать сложный файл JSON в простой файл JSON, используя JQ. Однако используемый мной запрос выдает неверный вывод.

Мой (урезанный) JSON-файл:

[
  {
    "id": 100,
    "foo": [
      {
        "bar": [
          {"type": "read"},
          {"type": "write"}
        ],
        "users": ["admin_1"],
        "groups": []
      },
      {
        "bar": [
          {"type": "execute"},
          { "type": "read"}
        ],
        "users": [],
        "groups": ["admin_2"]
      }
    ]
  },
  {
    "id": 101,
    "foo": [
      {
        "bar": [
          {"type": "read"}
        ],
        "users": [
          "admin_3"
        ],
        "groups": []
      }
    ]
  }
]

Мне нужно сгенерировать более плоский JSON-файл и объединить пользователей и группы в одно поле, похожее на это:

 [
  {
    "id": 100,
    "users_groups": [
      "admin_1",
      "admin_2"
    ],
    "bar": ["read"]
  },
  {
    "id": 100,
    "users_groups": ["admin_1"],
    "bar": ["write"]
  },
  {
    "id": 100,
    "users_groups": ["admin_2"],
    "bar": ["execute"]
  },
   {
    "id": 101,
    "users_groups": ["admin_3"],
    "bar": ["read"]
  }
 ]  

Все, что я пытаюсь сделать в JQ, приводит к тому, что я получаю неправильный вывод (где admin_1 неправильно имеет bar = execute, а admin_2 неправильно имеет bar = write), аналогично следующему:

[
  {
    "id": 100,
    "users_groups": [
      "admin_1",
      "admin_2"
    ],
    "bar": ["read", "write", "execute"]
  },
   {
    "id": 101,
    "users_groups": ["admin_3"],
    "bar": ["read"]
  }
 ] 

Я пробовал много вариантов этого запроса - есть идеи, что мне следует делать вместо этого?

    cat file.json | jq -r '[.[] | select(has("foo")) |{"id", "users":(.foo[] | .users), "groups":(.foo[] | .groups), "bar":([.foo[].bar[] | .type])} ] '

1 Ответ

0 голосов
/ 02 июля 2018

Следующие группы фильтров по типу, поскольку вопрос, кажется, требует:

map(.id as $id
    | [.foo[]
      | {id: $id, bar: .bar[].type} +
        {"users_groups": (.users + .groups)[]} ]
    | group_by(.bar)
    | map(.[0] + {"users_groups": [.[].users_groups]}) )

выход

[
  [
    {
      "id": 100,
      "bar": "execute",
      "users_groups": [
        "admin_2"
      ]
    },
    {
      "id": 100,
      "bar": "read",
      "users_groups": [
        "admin_1",
        "admin_2"
      ]
    },
    {
      "id": 100,
      "bar": "write",
      "users_groups": [
        "admin_1"
      ]
    }
  ],
  [
    {
      "id": 101,
      "bar": "read",
      "users_groups": [
        "admin_3"
      ]
    }
  ]
]

Изменения

Чтобы получить выходной формат массива объектов, просто нажмите | [.[][]]; Точно так же было бы тривиально легко убедиться, что .bar является массивом, хотя это может быть бессмысленно, учитывая, что группировка выполняется по .type.

...