Back to Graphql Platform

MongoDB

website/src/docs/hotchocolate/v16/integrations/mongodb.md

16.1.0-p.1.105.2 KB
Original Source

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.

Get Started

Install the HotChocolate.Data.MongoDb package:

<PackageInstallation packageName="HotChocolate.Data.MongoDb" />

MongoExecutable

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.

csharp
[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();
}

Filtering

Register the MongoDB filtering convention on the schema builder:

csharp
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:

graphql
query GetPersons {
  persons(
    where: {
      name: { eq: "Yorker Shorton" }
      addresses: { some: { street: { eq: "04 Leroy Trail" } } }
    }
  ) {
    name
    addresses {
      street
      city
    }
  }
}

Mongo Query:

json
{
  "find": "person",
  "filter": {
    "Name": { "$eq": "Yorker Shorton" },
    "Addresses": { "$elemMatch": { "Street": { "$eq": "04 Leroy Trail" } } }
  }
}

Sorting

Register the MongoDB sorting convention on the schema builder:

csharp
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:

graphql
query GetPersons {
  persons(order: [{ name: ASC }, { mainAddress: { city: DESC } }]) {
    name
    addresses {
      street
      city
    }
  }
}

Mongo Query:

json
{
  "find": "person",
  "filter": {},
  "sort": { "Name": 1, "MainAddress.City": -1 }
}

Projections

Register the MongoDB projection convention on the schema builder:

csharp
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:

graphql
query GetPersons {
  persons {
    name
    addresses {
      city
    }
  }
}

Mongo Query:

json
{
  "find": "person",
  "filter": {},
  "projection": { "Addresses.City": 1, "Name": 1 }
}

Paging

Register the MongoDB-specific pagination providers:

csharp
builder
    .AddGraphQL()
    .AddMongoDbPagingProviders();

Learn more about pagination providers

Cursor Pagination

Annotate your resolver with [UsePaging] or .UsePaging() to use cursor-based pagination:

csharp
[UsePaging]
public IExecutable<Person> GetPersons(IMongoCollection<Person> collection)
{
    return collection.AsExecutable();
}

Example query:

graphql
query GetPersons {
  persons(first: 50, after: "OTk=") {
    nodes {
      name
      addresses {
        city
      }
    }
    pageInfo {
      endCursor
      hasNextPage
      hasPreviousPage
      startCursor
    }
  }
}

FirstOrDefault / SingleOrDefault

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.

csharp
[UseFirstOrDefault]
public IExecutable<Person> GetPersonById(
    IMongoCollection<Person> collection, Guid id)
{
    return collection.Find(x => x.Id == id).AsExecutable();
}

Next Steps

<!-- spell-checker:ignore Shorton -->