Using Mongoose Queries in GraphQL

A GraphQL resolver can use Mongoose through a service or repository to retrieve documents.

For example:

const findUserById = async (id) => {
  return UserModel.findById(id).lean();
};

The lean() method returns plain JavaScript objects rather than full Mongoose documents. This can be useful for read-heavy GraphQL operations when you do not need Mongoose document methods, getters, setters, or change tracking.

A resolver might then be:

const resolvers = {
  Query: {
    user: (_, { id }) => findUserById(id)
  }
};

For lists:

const users = await UserModel
  .find({ isActive: true })
  .sort({ createdAt: -1 })
  .limit(20)
  .lean();

GraphQL selection sets create an important performance consideration. A client may request only:

users {
  id
  name
}

but a naive resolver may still retrieve every large document field from MongoDB.

For performance-sensitive systems, the server can sometimes inspect the GraphQL selection and translate it into a database projection. This should be done carefully because nested selections, aliases, fragments, authorization, computed fields, and resolver behavior make automatic projection non-trivial.

Do not prematurely build complex selection-to-database projection logic. Measure first and introduce it where the performance benefit justifies the complexity.

Mongoose Repository Query
const userRepository = {
  async findActiveUsers(limit = 20) {
    return UserModel
      .find({ isActive: true })
      .sort({ createdAt: -1 })
      .limit(limit)
      .lean();
  }
};

const resolvers = {
  Query: {
    users: (_, { limit }, context) => {
      return context.userRepository.findActiveUsers(limit);
    }
  }
};
💡 The repository owns the Mongoose query while the resolver delegates to it. lean() can reduce Mongoose document overhead for read-only use cases. In production, query limits should be bounded and indexes should support the filter and sort.
Key Takeaways
  • lean() can be useful for read-only Mongoose queries.
  • Database queries should be encapsulated behind application boundaries.
  • GraphQL selection sets do not automatically optimize MongoDB queries.
  • Indexes and bounded limits are important for production queries.
Knowledge Check

What is one common reason to use Mongoose's `lean()` for a GraphQL read operation?