How to use Mongoose with GraphQL and DataLoader?
Keep your mongoose schema in a separate module. You don't want to create your schema each request -- just the first time the module is imported.
const userSchema = new Schema({ name: String, friendIds: [String]})const User = mongoose.model("User", userSchema)module.exports = { User }
If you want, you can also export a function that creates your loader in the same module. Note, however, that we do not want to export an instance of a loader, just a function that will return one.
// ...const getUserLoader = () => new DataLoader((userIds) => { return User.find({ _id: { $in: userIds } }).execute()})module.exports = { User, getUserLoader }
Next, we want to include our loader in the context. How exactly this is done will depend on what library you're using to actually expose your graphql endpoint. In apollo-server
, for example, context is passed in as part of your configuration.
new ApolloServer({ typeDefs, resolvers, context: ({ req }) => ({ userLoader: getUserLoader() }),})
This will ensure that we have a fresh instance of the loader created for each request. Now, your resolvers can just call the loader like this:
const resolvers = { Query: { users: async (root, args, { userLoader }) => { // Our loader can't get all users, so let's use the model directly here const allUsers = await User.find({}) // then tell the loader about the users we found for (const user of allUsers) { userLoader.prime(user.id, user); } // and finally return the result return allUsers } }, User: { friends: async (user, args, { userLoader }) => { return userLoader.loadMany(user.friendIds) }, },}