I've created a GraphQLSchema with two fields, both using a resolve()
to get the data from a 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:
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
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. This is why you get Cannot read property 'collection' of undefined
because the parent resolver didn't return an object with a db
property.
args
are the argument passed to the field, like so: article(id:'someid')
when writing the query.
context
is a parameter that is passed to every resolver, and is mostly used to make accessible API-wide utilities, like your db
connection.
To have db
set inside your context, you can initialize your GraphQL server with it.
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.
title and outer content will both fire their request in parallel, accessing the db
in context
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With