在 GraphQL 中过滤嵌入式文档列表

Posted

技术标签:

【中文标题】在 GraphQL 中过滤嵌入式文档列表【英文标题】:Filter Embedded Document List in GraphQL 【发布时间】:2021-04-17 21:40:17 【问题描述】:

我正在使用 MongoDB 后端(通过 MongoEngine)在 Python/Graphene 中构建 GraphQL 应用程序。一切都运行良好,但注意到没有很多文档用于处理嵌入文档的嵌套列表。我认为 GraphQL 的一个强大功能是能够仅投影您想要的属性,但似乎并非完全如此。

以这个集合为例:

[
  
    "name": "John Doe",
    "age": 37,
    "preferences": [
      
        "key": "colour",
        "value": "Green"
      ,
      
        "key": "smell",
        "value": "onions cooking in butter"
      ,
      ...
    ]
  ,
  ...
]

如果我想通过 GraphQL 查找特定对象,我会通过类似的查询进行查找


    person(name: "John Doe")edgesnode
      name age preferencesedgesnode
        key value
      
    

但这可能会带回数百个嵌套文档。我想做的是将请求的嵌套文档标识为投影请求的一部分。


    person(name: "John Doe")edgesnode
      name age preferences(key: "colour")edgesnode
        key value
      
    

我阅读 GraphQL 规范的理解是这些子查询是不可能的,但想先与专家确认。如果可能的话,我将如何实现它来支持这些类型的请求?

更新也许架构示例会提供一些更有见地的响应。

class PreferenceModel(mongoengine.EmbeddedDocument):
    key = mongoengine.fields.StringField()
    value = mongoengine.fields.StringField()


class Preference(graphene_mongo.MongoengineObjectType):
    class Meta:
        interfaces = (graphene.relay.Node, )
        model = PreferenceModel


class PersonModel(mongoengine.Document):
    meta = 'collection': 'persons'
    name = mongoengine.fields.StringField()
    age = mongoengine.fields.IntField()
    preferences = mongoengine.fields.EmbeddedDocumentListField(PreferenceModel)


class Person(graphene_mongo.MongoengineObjectType):
    class Meta:
        interfaces = (graphene.relay.Node, )
        model = PersonModel


class Query(graphene.ObjectType):
    person = graphene_mongo.MongoengineConnectionField(Person)

schema = graphene.Schema(query=Query, types=[Person])
app = starlette.graphql.GraphQLApp(schema=schema)

使用上述结构,需要进行哪些更改才能允许对嵌套对象进行查询/过滤?

【问题讨论】:

可能...任何道具[在任何深度级别]都可以传递自己的参数...当道具/字段有自己的解析器时使用...在这种情况下preferences解析器将负责这个过滤 我也是这么想的。但如果我尝试类似于上面的查询,生成的嵌套列表是空的 实现/解析器/石墨烯/无论 - 不是 graphql - 问题 【参考方案1】:

我有一个类似的问题,但正在使用 graphene-django。我使用 DjangoObjectType 上的自定义解析器解决了它,如下所示:


import graphene
from graphene_django import DjangoObjectType
from .models import Question, Choice, SubChoice


class SubChoiceType(DjangoObjectType):
    class Meta:
        model = SubChoice
        fields = "__all__"


class ChoiceType(DjangoObjectType):
    sub_choices = graphene.List(SubChoiceType, search_sub_choices=graphene.String())

    class Meta:
        model = Choice
        fields = ("id", "choice_text", "question")

    def resolve_sub_choices(self, info, search_sub_choices=None):
        if search_sub_choices:
            return self.subchoice_set.filter(sub_choice_text__icontains=search_sub_choices)

        return self.subchoice_set.all()


class QuestionType(DjangoObjectType):
    choices = graphene.List(ChoiceType, search_choices=graphene.String())

    class Meta:
        model = Question
        fields = ("id", "question_text")

    def resolve_choices(self, info, search_choices=None):
        if search_choices:
            return self.choice_set.filter(choice_text__icontains=search_choices)

        return self.choice_set.all()


class Query(graphene.ObjectType):
    all_questions = graphene.List(QuestionType, search_text=graphene.String())
    all_choices = graphene.List(ChoiceType, search_text=graphene.String())
    all_sub_choices = graphene.List(SubChoiceType)

    def resolve_all_questions(self, info, search_text=None):
        qs = Question.objects.all()
        if search_text:
            qs = qs.filter(question_text__icontains=search_text)

        return qs

    def resolve_all_choices(self, info, search_text=None):
        qs = Choice.objects.all()
        if search_text:
            qs = qs.filter(choice_text__icontains=search_text)

        return qs

    def resolve_all_sub_choices(self, info):
        qs = SubChoice.objects.all()
        return qs


schema = graphene.Schema(query=Query)

您可以在此处找到示例:https://github.com/allangz/graphene_subfilters/blob/main/mock_site/polls/schema.py

它可能对你有用

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review

以上是关于在 GraphQL 中过滤嵌入式文档列表的主要内容,如果未能解决你的问题,请参考以下文章

过滤 MongoDB 中的嵌入式数组

如何从 Youtube 播放列表 API 中过滤掉不可嵌入的视频

MongoDB请求:仅从嵌入数组中的嵌入文档中过滤特定字段

在猫鼬中仅更改整个嵌入式文档数组的一个字段

在猫鼬中仅更改整个嵌入式文档数组的一个字段

如何使用文档客户端修改dynamodb中嵌入式列表中的元素