在 Python 中使用 GraphQL 过滤 JSON 数据

Posted

技术标签:

【中文标题】在 Python 中使用 GraphQL 过滤 JSON 数据【英文标题】:Using GraphQL to Filter a JSON Data in Python 【发布时间】:2021-01-06 22:18:26 【问题描述】:

我在我的 python 项目中使用官方的 graphene 包。我有一个来自正在运行的 Docker 容器检查命令的巨大嵌套 JSON 数据,我想从中获取一些字段。我可以逐个选择所有这些字段并将它们添加到这样的字典中:

def ContainerConfigs(configs):
    data = 
    data['Command'] = configs['Args'][-1]
    data['Hostname'] = configs['Config']['Hostname']
    data['Image'] = configs['Config']['Image']
    data['Distro'] = configs['Config']['Labels']['org.label-schema.name']
    data['WorkDir'] = configs['Config']['WorkingDir']
    data['IPAddress'] = configs['NetworkSettings']['Networks']['bridge']['IPAddress']

    return data

但这是一个弱解决方案。我认为可以使用 GraphQL 对其进行优化。没有服务器、请求和响应。我想创建它的Schema 类并发送参数(JSON 和查询)并让函数执行该查询并返回结果。像这样的:

import graphene

# I need to find this part of the code
# class Schema(..):
#     ...
# class Query(...):
#     ...

def ContainerConfigs(configs, query):
    schema = graphene.Schema(query=Query)
    # I need to find a way to pass the configs (Json data) to the Query class to
    # execute the query_string on the data
    query_string = """
    query 
        Args
        Config 
            Hostname
            Image
            WorkingDir
            Label
                org.label-schema.name
            
        
        NetworkSettings
            Networks
                bridge
                    IPAddress
                
            
        
    
    """
    result = schema.execute(query_string)
    
    return result

【问题讨论】:

您遇到了什么具体问题?一旦你检索到这些数据,你最终会用它做什么? 我正在尝试对数据执行查询并回复结果。 这里对我来说不明显的另一件事是 GraphQL 查询的结果将具有与输入数据相同的“形状”;您必须使用相同的嵌套字典语法来访问它。这似乎不是一项适合我的明显技术。 没有服务器? schema 用于服务器...如果您知道它是如何工作的,您可以模拟响应,它只是 json(将您的 json 转换为所需的响应形状),也许可以使用一些石墨烯部件...但您不知道它是如何工作的,先学吧 @DavidMaze 所以,你的意思是最好使用上面的脚本逐个选择所有这些字段?我认为会有一种更好的优化方法来从 python 中的 JSON 数据中获取这些任意字段。我认为 GraphQL 在这种情况下会很有帮助。我已经搜索了很多,但找不到任何合适的结果。其中大部分是关于 GraphQL 在 Django 或 Flask 等 Web 框架中的使用。 【参考方案1】:

这不是一个很好的技术匹配:您最终会以 GraphQL 语法重新创建大量 Docker API,并且在您查询后它仍然具有相同的嵌套字典布局。

原则上,您可以编写与Docker API 具有相同布局的 GraphQL 模式。架构是必需的;没有它你就无法进行 GraphQL 查询,但这基本上涉及在你的源代码中复制整个 Docker API 对象模型。这里要注意的另一件事是,对 GraphQL 查询的响应与查询具有相同的“形状”(例如,请参见 graphql.org 上的 Execution 页面)。

如果您完成了所有这些工作,并运行了您显示的 GraphQL 查询,您将获得类似的嵌套字典响应

result = schema.execute(query_string)
hostname = result.data['Config']['Hostname']

这并不比你已经拥有的更好。 (同样,请参阅 Graphene Execution 文档页面上的示例。)

如果您想提取这些数据并将其封装在某种对象中,您可以创建一个类来为您完成。我可能会这样写:

from collections import namedtuple

class ContainerConfigs(namedtuple('ContainerConfigs', ['command', 'hostname', ...])):
  @classmethod
  def from_docker_inspect(cls, configs):
    return cls(
      command=configs['Args'][-1],
      hostname=configs['Config']['Hostname'],
      ...
    )

info = ContainerConfigs.from_docker_inspect(configs)
print(f"container hostname (not generally useful): info.hostname")

【讨论】:

谢谢,让我更清楚地解释我的问题。想象一下,你有一个巨大的 JSON 数据。您需要返回该数据的 150 个字段中的 50 个。获得这 50 个字段的最佳方法是什么?您是逐个获取它们并将它们添加到五十行的字典中(例如 -> data = configs['something'])还是做得更好? 如果 server 支持 GraphQL 端点,您只能请求这 50 个特定字段,但尝试运行 GraphQL 查询没有多大意义(没有解析器或其他行为)在您已有的 JSON 对象上。另一种方法可能是对象外观,它在其__init__ 方法中获取 JSON blob,并使用其他方法从中返回特定属性。或者,只编写没有相应类的提取器函数。

以上是关于在 Python 中使用 GraphQL 过滤 JSON 数据的主要内容,如果未能解决你的问题,请参考以下文章

如何使用`django-filters`编写将在整数字段上使用范围过滤器的GraphQL查询?

GraphQL 食谱示例中的 Django 过滤器错误

如何在 Sangria 中使用 graphql 查询过滤列表响应

使用 GraphQL 变量和 Next JS 过滤数组中的数据

如何在 GraphQL 中过滤大于

如何在 graphql 查询中按文件扩展名过滤