简体   繁体   English

如何在模式中嵌套两个graphQL查询?

[英]How to nest two graphQL queries in a schema?

I've created a GraphQLSchema with two fields, both using a resolve() to get the data from a mongoDB. 我创建了一个包含两个字段的GraphQLSchema ,它们都使用resolve()从mongoDB获取数据。

With that, the query... 有了它,查询......

{
  article(id: "Dn59y87PGhkJXpaiZ") {
    title
  },
  articleContent(id: "Dn59y87PGhkJXpaiZ") {
    _id,
    content(language: "en"),
    type
  }
}

...results in: ...结果是:

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

But I need a result structure like this (content should be inside of article object): 但我需要这样的结果结构(内容应该在文章对象内):

Expected result 预期结果

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

For me the problem are both async mongoDB resolves in my schema: 对我来说,问题是异步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()
        }
      }
    }
  })
})

Update 更新

If I nest the content inside the article, I do get the error Cannot read property 'collection' of undefined 如果我在文章中嵌入内容,我确实得到错误Cannot read property 'collection' of undefined

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 })
        }
      }
    }
  })
})

First, let's analyze the signature of a resolver. 首先,让我们分析解析器的签名。

function resolve(root, args, context)

root is the value returned by the parent resolver. root是父解析器返回的值。 This is why you get Cannot read property 'collection' of undefined because the parent resolver didn't return an object with a db property. 这就是你Cannot read property 'collection' of undefined原因,因为父解析器没有返回带有db属性的对象。

args are the argument passed to the field, like so: article(id:'someid') when writing the query. args是传递给字段的参数,如下所示: article(id:'someid')在编写查询时。

context is a parameter that is passed to every resolver, and is mostly used to make accessible API-wide utilities, like your db connection. context是传递给每个解析程序的参数,主要用于创建可访问的API范围的实用程序,例如db连接。

To have db set inside your context, you can initialize your GraphQL server with it. 要在上下文中设置db ,可以使用它初始化GraphQL服务器。

app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  context: {
    db: db
  },
  graphiql: true,
}));

About the nesting now, you could have something like this. 关于嵌套现在,你可以有这样的东西。

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,
                  }
                }
              })),
            }
          }
        }),
      }
    }
  })
})

In order, this will happen: 按顺序,这将发生:

  • article gets its parameter id and returns it, giving it to children resolvers. article获取其参数id并返回它,将其提供给子解析器。

  • title and outer content will both fire their request in parallel, accessing the db in context . 标题和外部内容将同时触发它们的请求,在context访问db

  • when outer content gets back from the db, the inner content field of every element will use their parameter language to return the right result. 当外部内容从db返回时,每个元素的内部内容字段将使用其参数language来返回正确的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM