website/src/docs/hotchocolate/v16/integrations/mongodb.md
Hot Chocolate has a data integration for MongoDB. With this integration, you can translate paging, filtering, sorting, and projections directly into native MongoDB queries.
You can find an example project in Hot Chocolate Examples.
Install the HotChocolate.Data.MongoDb package:
The integration builds around IExecutable<T>. The AsExecutable extension method is available on IMongoCollection<T>, IAggregateFluent<T>, and IFindFluent<T>. The execution engine picks up the IExecutable and executes it efficiently. You can use any aggregation or find pipeline before calling AsExecutable.
[UsePaging]
[UseProjection]
[UseSorting]
[UseFiltering]
public IExecutable<Person> GetPersons(IMongoCollection<Person> collection)
{
return collection.AsExecutable();
}
[UseFirstOrDefault]
public IExecutable<Person> GetPersonById(
IMongoCollection<Person> collection, Guid id)
{
return collection.Find(x => x.Id == id).AsExecutable();
}
Register the MongoDB filtering convention on the schema builder:
builder
.AddGraphQL()
.AddQueryType<Query>()
.AddMongoDbFiltering();
To use MongoDB filtering alongside
IQueryable/IEnumerable, register the MongoDB convention under a different scope:AddMongoDbFiltering("yourScope"). Then specify the scope on each resolver:[UseFiltering(Scope = "yourScope")].
Filters are converted to BsonDocuments and applied to the executable.
GraphQL Query:
query GetPersons {
persons(
where: {
name: { eq: "Yorker Shorton" }
addresses: { some: { street: { eq: "04 Leroy Trail" } } }
}
) {
name
addresses {
street
city
}
}
}
Mongo Query:
{
"find": "person",
"filter": {
"Name": { "$eq": "Yorker Shorton" },
"Addresses": { "$elemMatch": { "Street": { "$eq": "04 Leroy Trail" } } }
}
}
Register the MongoDB sorting convention on the schema builder:
builder
.AddGraphQL()
.AddQueryType<Query>()
.AddMongoDbSorting();
To use MongoDB sorting alongside
IQueryable/IEnumerable, register the MongoDB convention under a different scope:AddMongoDbSorting("yourScope"). Then specify the scope on each resolver:[UseSorting(Scope = "yourScope")].
Sorting is converted to BsonDocuments and applied to the executable.
GraphQL Query:
query GetPersons {
persons(order: [{ name: ASC }, { mainAddress: { city: DESC } }]) {
name
addresses {
street
city
}
}
}
Mongo Query:
{
"find": "person",
"filter": {},
"sort": { "Name": 1, "MainAddress.City": -1 }
}
Register the MongoDB projection convention on the schema builder:
builder
.AddGraphQL()
.AddQueryType<Query>()
.AddMongoDbProjections();
To use MongoDB projections alongside
IQueryable/IEnumerable, register the MongoDB convention under a different scope:AddMongoDbProjections("yourScope"). Then specify the scope on each resolver:[UseProjection(Scope = "yourScope")].
Projections do not always improve performance. Even though MongoDB processes and transfers less data, projections can sometimes harm query performance. See this article by Tek Loon for guidance on when to use them.
GraphQL Query:
query GetPersons {
persons {
name
addresses {
city
}
}
}
Mongo Query:
{
"find": "person",
"filter": {},
"projection": { "Addresses.City": 1, "Name": 1 }
}
Register the MongoDB-specific pagination providers:
builder
.AddGraphQL()
.AddMongoDbPagingProviders();
Learn more about pagination providers
Annotate your resolver with [UsePaging] or .UsePaging() to use cursor-based pagination:
[UsePaging]
public IExecutable<Person> GetPersons(IMongoCollection<Person> collection)
{
return collection.AsExecutable();
}
Example query:
query GetPersons {
persons(first: 50, after: "OTk=") {
nodes {
name
addresses {
city
}
}
pageInfo {
endCursor
hasNextPage
hasPreviousPage
startCursor
}
}
}
To return a single object from a collection, use the UseFirstOrDefault or UseSingleOrDefault middleware. Hot Chocolate rewrites the field type from a list to an object type.
[UseFirstOrDefault]
public IExecutable<Person> GetPersonById(
IMongoCollection<Person> collection, Guid id)
{
return collection.Find(x => x.Id == id).AsExecutable();
}
IExecutable abstraction