Фильтровать объект по свойству и выбрать с помощью ключа в jmespath

Я пытаюсь фильтровать свойства объекта в jmespath на основе значения подзадачи и хочу включать только те свойства где для подзадачи задано определенное значение.

На основании данных примера:

{
  "a": {
    "feature": {
      "enabled": true,
    }
  },
  "b": {
  },
  "c": {
    "feature": {
      "enabled": false
     }
  }
}

Я хотел бы получить объект со всеми свойствами, в которых функция включена.

{
  "a": {
    "feature": {
      "enabled": true,
    }
  }
}

Я решил, что могу использовать этот запрос jmespath для фильтрации объектов, где property. enabled установлено значение true. Unfortunateley, похоже, не работает и вместо этого возвращает пустой массив.

*[?feature.enabled==`true`]

*.feature.enabled или *[feature.enabled] возвращает только логические значения без какого-либо контекста.

Даже если *[?feature.enabled== true ] будет работать, это будет просто массив значений свойств, но мне нужны ключи (a и c). Есть ли способ сделать это в jmespath?

Это все часть незанятой пьесы, поэтому, конечно, есть способ добиться выбора по-другому (шаблоны Jinja2 или пользовательский плагин), но я хотел попробовать jmespath и рассуждать, что он должен быть способен на такой задача.

Ответ 1

Извините, но AFAIK это невозможно в родном JMESPath.
Для этой цели существуют специальные встроенные функции в различных инструментах, таких как to_entries в jq.
Для jmespath.py и, следовательно, для Ansible существует зависание pull request для реализации манипуляций с ключами.

Обновление: Я сделал исправленную версию фильтра json_query.
Подробнее см. .

Ответ 2

С dict2items фильтра dict2items в Ansible 2.5 и более поздних версиях вы можете сделать это с помощью:

- debug:
    msg: "{{ dict(my_data | dict2items | json_query('[?value.feature.enabled].[key, value]')) }}"

Результат:

"msg": {
    "a": {
        "feature": {
            "enabled": true
        }
    }
}

Ответ 3

Краткий ответ (TL; DR)

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

пример

Следующий (слишком длинный) запрос jmespath к исходным данным в OP...

[
  {
      "item_key":           'a'
      ,"feature_enabled":   @.a.feature.enabled
      ,source_object:       @.a
  }
  ,{
      "item_key":           'b'
      ,"feature_enabled":   @.b.feature.enabled
      ,source_object:       @.b
  }
  ,{
      "item_key":           'c'
      ,"feature_enabled":   @.c.feature.enabled
      ,source_object:       @.c
  }
]|[? feature_enabled == 'true']

... дает следующий результат

[
  {
    "item_key": "a",
    "feature_enabled": true,
    "source_object": {
      "feature": {
        "enabled": true
      }
    }
  }
]

Это идентично или существенно похоже на желаемый результат, но тот факт, что нам пришлось согнуть наш мозг, чтобы добраться до него, говорит о том, что мы пытаемся протолкнуть квадратный колышек через круглое отверстие.

Ловушки

Причина, по которой этот запрос jmespath выглядит настолько длинным и громоздким, заключается в том, что сам исходный набор данных плохо нормализован для общего запроса jmespath.

Это потому, что он использует ключи объекта в качестве метода сопоставления верхнего уровня, когда последовательного индексированного списка было бы достаточно.

Когда у вас есть набор данных, который может содержать произвольное количество значений, почти всегда предпочтительнее использовать последовательность для сопоставления верхнего уровня вместо ключей объекта.

Если вы обнаружите, что вы можете что-то сделать в jmespath, но вам нужно изменять запрос jmespath всякий раз, когда вы добавляете еще одну "запись" в "набор записей произвольной (не фиксированной) длины", вы боретесь с Jmespath, а не работаете с ним,

Всякий раз, когда вы видите запрос, который кажется "невозможным выполнить" с помощью Jmespath, вы почти наверняка имеете дело со структурой данных, использующей объекты, где последовательности могут быть более подходящими.

Ключи объекта обычно означают фиксированное количество свойств, которые jmespath может обрабатывать просто отлично.

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

Вещи начинают становиться некомфортными, когда вы обнаруживаете, что вам необходимо создавать последовательности объектов, чтобы обойти объекты-объекты... что вполне выполнимо в jmespath, но это будет болезненно.

Смотрите также