Reputation: 344
I write this code in nodejs and graphQL server. I had 2 collection in mongodb; Stars and Movies. Stars save information about Stars that act in top movies. and Movie collection save information about each movie. when i query movie this code return to me all movie that saved in my database. but how can I modified this code that when i search stars or movies by a specific id this code can return to me a single user or star?
this is my schema :
const {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLNonNull,
GraphQLList,
GraphQLFloat
} = require("graphql");
const {Movie, User} = require('/home/fateme/imdb_final/db')
const starType = new GraphQLObjectType({
name: "UserType",
fields: {
name: {
type: GraphQLString,
async resolve(objId) {
const starFind = await User.findOne({ _id: objId})
return starFind.name
}
},
imdbId: {
type: GraphQLString,
async resolve(objId) {
const starFind = await User.findOne({ _id: objId})
return starFind.imdbId
}
}
}
});
const movieType = new GraphQLObjectType({
name: "MovieType",
fields: {
title: {
type: GraphQLString,
async resolve(objId) {
const movieFind = await Movie.findOne({ _id: objId._id})
return movieFind.title
}
},
year: {
type: GraphQLInt,
async resolve(objId) {
const movieFind = await Movie.findOne({ _id: objId._id})
return movieFind.year
}
},
rate: {
type: GraphQLFloat,
async resolve(objId) {
const movieFind = await Movie.findOne({ _id: objId._id})
return movieFind.rating
}
},
// rank: {
// type: GraphQLInt,
// async resolve(objId) {
// const movieFind = await Movie.findOne({ _id: objId._id})
// return movieFind.rank
// }
// },
director: {
type: starType,
async resolve(objId) {
return objId.director
// return userFind.name
}
},
stars: {
type: GraphQLList(starType),
async resolve(objId) {
return objId.stars
// return userFind.name
}
},
}
});
const queryType = new GraphQLObjectType({
name: 'Query',
fields: () => ({
users: {
type: GraphQLList(starType),
async resolve() {
const allStar = await User.find({})
return allStar._id
}
},
movies: {
type: GraphQLList(movieType),
async resolve() {
const allMovie = await Movie.find({})
return allMovie
}
},
})
});
const schema = new GraphQLSchema({
query: queryType
});
module.exports = schema;
Upvotes: 0
Views: 1201
Reputation: 159428
In graphql-js, you can set up an object type that's backed by a JavaScript class object. If you do that, you don't need to provide separate resolvers for class methods; a GraphQL field that matches a class method will just directly call that method and use the results.
The GraphQL server library you're using will take responsibility for unpacking a list-of-objects response to a GraphQL list type, and dispatching resolver calls to a specific object from that list as required.
In any implementation language, a good general pattern for GraphQL is this:
Root-level resolvers (your Query
and Mutation
types) find specific objects; and
Object-level resolvers (in your example, UserType
and MovieType
) act on known specific objects that already have a programming-language-level representation.
That is, if you're in a resolver function for some specific type, you don't need to look up that object again; you should already have it (in your case from the root query resolvers).
Your resolver implementations make it clear that your objects already have fields that match the GraphQL field names, so the two changes you need to make are making the root-level resolver provide the specific object:
const root = {
users: async () => User.find({}),
movies: async () => Movie.find({})
}
and just provide a schema that directly reflects the pre-existing object layout:
const schema = buildSchema(`
type UserType {
name: String
imdbId: String
}
type MovieType {
title: String
year: Int
rating: Float
# rank: Int
director: StarType
stars: [StarType]
}
type Query {
users: [UserType]
movies: [MovieType]
}
`)
For the code you've shown, nothing requires a custom resolver, except that you try to rename the rating
field to rate
. In graphql-js I believe you need to provide an actual object that has the actual field names you want, and I've found it often makes sense to have a separate set of objects that directly reflect the GraphQL API that you want.
In my experience, if it's possible to use the GraphQL schema language, you should do so: it is much more compact and readable than an object-based representation of the same types.
Upvotes: 2