Могу ли я вывести логическое значение на основе значений в списке?

#json #csv #boolean #jq #indicator

#json #csv #логическое #jq #индикатор

Вопрос:

Редактировать: я использовал решение, предоставленное @peak, для выполнения следующего:

 $ jq -r --argjson whitelist '["role1", "role2"]' '
select(has("roles") and any(.roles[]; . == "role1" or . == "role2"))
| (reduce ."roles"[] as $r ({}; .[$r]=true)) as $roles
| [.email, .username, .given_name, .family_name, ($roles[$whitelist[]]
| . != null)]
| @csv
' users.json
 

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

Сценарий: профили пользователей в виде документов JSON, где у каждого профиля есть объект списка с назначенными им ролями. Пример:

 {
  "username": "janedoe",
  "roles": [
    "role1",
    "role4",
    "role5"
  ]
}
 

Фактический файл данных представляет собой файл ndjson, один пользовательский объект, как указано выше, на строку.

Меня интересуют только определенные роли, скажем role1 , role3 , и role4 . Я хочу создать CSV в формате:

 username,role1?,role3?,role4?
 

например,

 janedoe,true,false,true
 

Часть, которую я не понял, заключается в том, как выводить логические значения или Y / N в ответ на значения в объекте списка. Это то, что я могу сделать сам по jq себе?

Комментарии:

1. Ваш оператор select — это не то, что вы думаете. Рассмотрим вместо этого: select(has("roles") and any(.roles[] == $whitelist[]; true)) . Пожалуйста, исправьте это.

Ответ №1:

С вашим вводом вызов:

 jq -r --argjson whitelist '["role1", "role3", "role4"]' '
  (["username"]   $whitelist),
  [.username, ($whitelist[] as $w | .roles | index([$w]) != null)]
  | @csv
'
 

выдает:

 "username","role1","role3","role4"
"janedoe",true,false,true

 

Примечания:

  1. Предпоследняя строка приведенного выше фильтра jq может быть сокращена до:

    [.username, (.roles | index($whitelist[]) != null)]

  2. Предположительно, если бы было более одного пользователя, вам понадобилась бы строка заголовка только один раз, и в этом случае вышеуказанное решение необходимо было бы изменить.

Использование В/1

Поскольку index/1 это не так эффективно, как могло бы быть, вы можете рассмотреть эту альтернативу:

   (["username"]   $whitelist),
  (.roles as $roles | [.username, ($whitelist[] | IN($roles[]) )])
  | @csv
 

Использование словаря JSON

Если количество ролей было очень большим, то, вероятно, было бы более эффективно создать словарь JSON, чтобы избежать повторных линейных поисков:

   (reduce .roles[] as $r ({}; .[$r]=true)) as $roles
  | (["username"]   $whitelist),
    [.username, ($roles[$whitelist[]] != null)]
  | @csv
 

С ndjson в качестве входных данных

Для повышения эффективности и обеспечения наличия только одного заголовка вы могли бы использовать inputs опцию командной строки -n . Добавив дополнительные поля, упомянутые в пересмотренном Q, вы можете получить:

 jq -nr --argjson whitelist '["role1", "role2"]' '
  ["email", "username", "given_name", "family_name"] as $greenlist
  | ($greenlist   $whitelist),
    (inputs 
     | select(has("roles") and any(.roles[] == $whitelist[]; true))
     | (reduce ."roles"[] as $r ({}; .[$r]=true)) as $roles
     | [ .[$greenlist[]], ($roles[$whitelist[]] != null) ])
  | @csv
' users.json

 

Комментарии:

1. Я получаю интересный побочный эффект: для некоторых пользователей я получаю одну строку вывода для каждой роли, которая у них есть. 5 ролей = 5 идентичных строк в выходных данных. Но это происходит только для некоторых пользователей. На данный момент я не уверен, чем они отличаются друг от друга, если вообще чем-то отличаются. Достаточно легко исправить , пробежав через sort и. uniq

2. Ваше select утверждение — это не то, что вы думаете. Вместо этого рассмотрим: select(any(.roles[]; . == "r" or . == "s"))

3. Кажется, мне все еще нужно has() предложение, но в некоторых записях нет roles[] списка. Есть ли в этом смысл? W / o has() я получаю «Невозможно выполнить итерацию по null» для некоторых записей. Кажется, это работает (ожидаемое количество результатов, никаких дубликатов): select(has("roles") and any(.roles[]; ... . Файл данных — это ndjson если это имеет значение.

4. Обязательно включите has условие (как я предложил в комментарии, прикрепленном непосредственно к Q), хотя вы можете счесть select(.roles and any(...)) достаточным.