如何在一个schema中嵌套两个GraphQL查询?

5
我已经创建了一个包含两个字段的GraphQLSchema,这两个字段都使用resolve()从mongoDB获取数据。
通过这个,查询...
{
  article(id: "Dn59y87PGhkJXpaiZ") {
    title
  },
  articleContent(id: "Dn59y87PGhkJXpaiZ") {
    _id,
    content(language: "en"),
    type
  }
}

...导致结果为:

{
  "data": {
    "article": {
      "title": "Sample Article"
    },
    "articleContent": [
      {
        "_id": "Kho2N8yip3uWj7Cib",
        "content": "group",
        "type": "group"
      },
      {
        "_id": "mFopAj4jQQuGAJoAH",
        "content": "paragraph",
        "type": null
      }
    ]
  }
}

但我需要一个像这样的结果结构(内容应该在文章对象内):
期望结果
{
  "data": {
    "article": {
      "title": "Sample Article",
      "content": [
        {
          "_id": "Kho2N8yip3uWj7Cib",
          "content": "group",
          "type": "group"
        },
        {
          "_id": "mFopAj4jQQuGAJoAH",
          "content": "paragraph",
          "type": null
        }
      ]
    },
  }
}

对我而言,问题在于我的模式中存在异步的mongoDB解析。

export default new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'RootQueryType',
    fields: {

      article: {
        type: new GraphQLObjectType({
          name: 'article',
          fields: {
            title: {
              type: GraphQLString,
              resolve (parent) {
                return parent.title
              }
            }
          }
        }),
        args: {
          id: { type: new GraphQLNonNull(GraphQLID) }
        },
        async resolve ({ db }, { id }) {
          return db.collection('content').findOne({ _id: id })
        }
      },

      articleContent: {
        type: new GraphQLList(new GraphQLObjectType({
          name: 'articleContent',
          fields: {
            _id: { type: GraphQLID },
            type: { type: GraphQLString },
            content: {
              type: GraphQLString,
              args: {
                language: { type: new GraphQLNonNull(GraphQLString) }
              },
              resolve (parent, { language }, context) {
                return parent.content[language][0].content
              }
            }
          }
        })),
        args: {
          id: { type: new GraphQLNonNull(GraphQLID) }
        },
        async resolve ({ db }, { id }) {
          return db.collection('content').find({ main: id }).toArray()
        }
      }
    }
  })
})

更新

如果我将内容嵌套在文章中,会出现错误无法读取未定义的属性“collection”

export default new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'RootQueryType',
    fields: {

      article: {
        type: new GraphQLObjectType({
          name: 'article',
          fields: {
            title: {
              type: GraphQLString,
              resolve (parent) {
                return parent.title
              }
            },
            articleContent: {
              type: new GraphQLList(new GraphQLObjectType({
                name: 'articleContent',
                fields: {
                  _id: { type: GraphQLID },
                  type: { type: GraphQLString },
                  content: {
                    type: GraphQLString,
                    args: {
                      language: { type: new GraphQLNonNull(GraphQLString) }
                    },
                    resolve (parent, { language }, context) {
                      return parent.content[language][0].content
                    }
                  }
                }
              })),
              args: {
                id: { type: new GraphQLNonNull(GraphQLID) }
              },
              async resolve ({ db }, { id }) { // db is undefined here!!
                return db.collection('content').find({ main: id }).toArray()
              }
            }
          }
        }),
        args: {
          id: { type: new GraphQLNonNull(GraphQLID) }
        },
        async resolve ({ db }, { id }) {
          return db.collection('content').findOne({ _id: id })
        }
      }
    }
  })
})

你的查询和模式定义匹配,这就是你得到的输出。将内容类型嵌套在文章类型中以获得嵌套结构,你可以有单独的解析器根据参数从自己的集合中提取文章和内容。 - s7vr
你说的“独立解析器”是什么意思?能否请您贴一些代码? - user3142695
我可以翻译,但我不太清楚您为什么要这样查询。为什么不使用像 String query = { article(id: "Dn59y87PGhkJXpaiZ") { _id, content(language:"en") { content, timestamp } } } 这样的查询,并根据此处所示更新您的模式以将内容嵌入文章中。我在那里还添加了一个完整的工作Java示例。请看一下并尝试解释这与该帖子有何不同。 - s7vr
你的链接代码和我正在使用的几乎一样。通过它,我可以获得在这个例子中将会是articleContent的数组,并且它的数据来自于find({ main: args.id })。此外,我需要数据集的标题。这些数据来自于另一个文档的find({_id: args.id})。这就是让我感到困扰的地方。 - user3142695
我尝试将内容嵌套到文章中,但是得到了一个未定义的数据库。请参见更新的帖子。 - user3142695
你是否在寻找这种结构?{ "data": { "article": [ { "_id": "9uPjYoYu58WM5Tbtf", "title": "parent", "content": [ { "content": "第三段", "timestamp": 1484939404 } ] }, { "_id": "345869696665", "title": "parent", "content": [ { "content": "第一段", "timestamp": 1484939404 } ] } ] } } - s7vr
1个回答

2

首先,让我们分析解析器的签名。

function resolve(root, args, context)
root是父级解析器返回的值。这就是为什么你会得到Cannot read property 'collection' of undefined的错误,因为父级解析器没有返回一个带有db属性的对象。 args是传递给字段的参数,例如在编写查询时:article(id:'someid')context是传递给每个解析器的参数,主要用于使API范围内的实用程序可访问,如您的db连接。
要在上下文中设置db,可以使用它初始化GraphQL服务器。
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  context: {
    db: db
  },
  graphiql: true,
}));

关于嵌套,你可以像这样做:

现在关于嵌套,你可以像这样做。

export default new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'RootQueryType',
    fields: {
      article: {
        args: {
          id: { type: new GraphQLNonNull(GraphQLID) }
        },
        resolve (_, { id }) {
          return id; // will make it accessible to children resolvers
        }
        type: new GraphQLObjectType({
          name: 'article',
          fields: {
            title: {
              async resolve (id /* resolved by article */, _, { db } /* db from context */) {
                const article = await db.collection('content').findOne({ _id: id });
                return article.title;
              }
              type: GraphQLString,
            },
            content: {
              async resolve (id /* resolved by article */, _, { db } /* db from context */) {
                const contents = await db.collection('content').find({ main: id }).toArray();
                return contents;
              }
              type: new GraphQLList(new GraphQLObjectType({
                name: 'articleContent',
                fields: {
                  _id: { type: GraphQLID },
                  type: { type: GraphQLString },
                  content: {
                    args: {
                      language: { type: new GraphQLNonNull(GraphQLString) }
                    },
                    aync resolve (parent /* resolved in content */, { language }) {
                      return parent.content[language][0].content
                    }
                    type: GraphQLString,
                  }
                }
              })),
            }
          }
        }),
      }
    }
  })
})

按顺序进行以下操作:

  • 获取文章的参数id并将其返回,将其提供给子解析器。

  • 标题和外部内容将同时并行请求,访问context中的db

  • 当外部内容从数据库返回时,每个元素的内部内容字段将使用它们的参数language返回正确的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接