Skip to main content

Aggregations

When aggregations are enabled nestjs-query will expose a new query that enables using the following common aggregations count, avg, sum, min, and max.

note

Only fields decorated with @FilterableField will be exposed in aggregate queries.

All examples will be based on the following TodoItem DTO. All fields except age, because it is not decorated with @FilterableField or @IDField, will be exposed in aggregate queries.

todo-item/dto/todo-item.dto.ts
import { FilterableField, IDField } from '@nestjs-query/query-graphql';import { ObjectType, ID, GraphQLISODateTime, Field } from '@nestjs/graphql';
@ObjectType('TodoItem')export class TodoItemDTO {  @IDField(() => ID)  id!: number;
  @FilterableField()  title!: string;
  @FilterableField({ nullable: true })  description?: string;
  @FilterableField()  completed!: boolean;
  @FilterableField(() => GraphQLISODateTime)  created!: Date;
  @FilterableField(() => GraphQLISODateTime)  updated!: Date;
  @Field()  age!: number;
  @FilterableField()  priority!: number;}

Enabling Aggregate Queries#

To enable aggregate queries you can set the enableAggregate option in your resolver

todo-item/todo-item.module.ts
import { NestjsQueryGraphQLModule } from '@nestjs-query/query-graphql';import { NestjsQueryTypeOrmModule } from '@nestjs-query/query-typeorm';import { Module } from '@nestjs/common';import { TodoItemInputDTO } from './dto/todo-item-input.dto';import { TodoItemUpdateDTO } from './dto/todo-item-update.dto';import { TodoItemDTO } from './dto/todo-item.dto';import { TodoItemEntity } from './todo-item.entity';
@Module({  imports: [    NestjsQueryGraphQLModule.forFeature({      imports: [NestjsQueryTypeOrmModule.forFeature([TodoItemEntity])],      resolvers: [        {          DTOClass: TodoItemDTO,          EntityClass: TodoItemEntity,          CreateDTOClass: TodoItemInputDTO,          UpdateDTOClass: TodoItemUpdateDTO,          enableAggregate: true        },      ],    }),  ],})export class TodoItemModule {}

All aggregate queries use the following naming convention ${objectName}Aggregate.

Below is a fragment from the generated schema for TodoItem

info

nestjs-query will only expose number fields for avg and sum.

type Query {  todoItem(id: ID!): TodoItem  todoItems(    paging: CursorPaging = { first: 10 }
    filter: TodoItemFilter = {}
    sorting: [TodoItemSort!] = []  ): TodoItemConnection!  todoItemAggregate(filter: TodoItemAggregateFilter): [TodoItemAggregateResponse!]!}
input TodoItemAggregateFilter {  and: [TodoItemAggregateFilter!]  or: [TodoItemAggregateFilter!]  id: IDFilterComparison  title: StringFieldComparison  description: StringFieldComparison  completed: BooleanFieldComparison  created: DateFieldComparison  updated: DateFieldComparison  priority: NumberFieldComparison}
type TodoItemAggregateResponse {  groupBy: TodoItemAggregateGroupBy  count: TodoItemCountAggregate  sum: TodoItemSumAggregate  avg: TodoItemAvgAggregate  min: TodoItemMinAggregate  max: TodoItemMaxAggregate}
type TodoItemAvgAggregate {  id: Float  priority: Float}
type TodoItemAggregateGroupBy {  id: ID  title: String  description: String  completed: Boolean  created: DateTime  updated: DateTime  priority: Float  createdBy: String  updatedBy: String}
type TodoItemCountAggregate {  id: Int  title: Int  description: Int  completed: Int  created: Int  updated: Int  priority: Int}
type TodoItemMaxAggregate {  id: ID  title: String  description: String  created: DateTime  updated: DateTime  priority: Float}
type TodoItemMinAggregate {  id: ID  title: String  description: String  created: DateTime  updated: DateTime  priority: Float}
type TodoItemSumAggregate {  id: Float  priority: Float}

Examples#

Basic#

{  todoItemAggregate {    count {      id    }    sum {      id    }    avg {      id    }    min {      id      title      created    }    max {      id      title      created    }  }}

With GroupBy#

To group your aggregate queries you can add a groupBy to specify one or more fields to group on.

{  todoItemAggregate {    groupBy {      completed    }    count {      id    }    sum {      id    }    avg {      id    }    min {      id      title      created    }    max {      id      title      created    }  }}

With Filter#

You can also provide a filter to only aggregate on a subset of data.

{  todoItemAggregate(filter: { completed: { is: false } }) {    count {      id    }    min {      id      title      created    }    max {      id      title      created    }  }}

When using the count aggregate only non-null fields will be counted.

For example assume description is null for all todo items you will get 0 back.

{  todoItemAggregate(filter: { completed: { is: false } }) {    count {      id      title      description    }  }}

Aggregating Relations#

When using the enableAggregate option any defined many relations will also expose a aggregate query {relationName}Aggregate

Building on the previous example assume TodoItem has a subTasks connection.

The following schema fragment will be created

type TodoItem {  id: ID!  title: String!  description: String  completed: Boolean!  created: DateTime!  updated: DateTime!  age: Float!  priority: Float!  subTasks(    paging: CursorPaging = { first: 10 }
    filter: SubTaskFilter = {}
    sorting: [SubTaskSort!] = []  ): TodoItemSubTasksConnection!  subTasksAggregate(    filter: SubTaskAggregateFilter  ):[ TodoItemSubTasksAggregateResponse!]!}
type TodoItemSubTasksAggregateResponse {  groupBy: TodoItemSubTasksAggregateGroupBy  count: TodoItemSubTasksCountAggregate  sum: TodoItemSubTasksSumAggregate  avg: TodoItemSubTasksAvgAggregate  min: TodoItemSubTasksMinAggregate  max: TodoItemSubTasksMaxAggregate}
type TodoItemSubTasksAggregateGroupBy {  id: ID  title: String  description: String  completed: Boolean  created: DateTime  updated: DateTime  todoItemId: String  createdBy: String  updatedBy: String}
type TodoItemSubTasksAvgAggregate {  id: Float}
type TodoItemSubTasksCountAggregate {  id: Int  title: Int  description: Int  completed: Int  created: Int  updated: Int  todoItemId: Int}
type TodoItemSubTasksMaxAggregate {  id: ID  title: String  description: String  created: DateTime  updated: DateTime  todoItemId: String}
type TodoItemSubTasksMinAggregate {  id: ID  title: String  description: String  created: DateTime  updated: DateTime  todoItemId: String}
type TodoItemSubTasksSumAggregate {  id: Float}

Examples#

Basic#

In this example we'll aggregate on all related subTasks.

{  todoItem(id: 5) {    subTasksAggregate {      count {        id      }      sum {        id      }      avg {        id      }      min {        id        title      }      max {        id        title      }    }  }}

With GroupBy#

In this example we'll aggregate on all related subTasks and group by completed.

{  todoItem(id: 5) {    subTasksAggregate {      groupBy {        completed      }      count {        id      }      sum {        id      }      avg {        id      }      min {        id        title      }      max {        id        title      }    }  }}

With Filter#

This example will aggregate all related subTasks that are not completed.

{  todoItem(id: 5) {    subTasksAggregate(filter: { completed: { is: false } }) {      count {        id      }      min {        id        title      }      max {        id        title      }    }  }}

Advanced#

Enabling Aggregates Only For Root#

When using the enableAggregate option it will enable aggregates on the root type as well as all relations. If you only want to expose aggregate functionality on the root type you can specify the aggregate option.

import { NestjsQueryGraphQLModule } from '@nestjs-query/query-graphql';import { NestjsQueryTypeOrmModule } from '@nestjs-query/query-typeorm';import { Module } from '@nestjs/common';import { TodoItemInputDTO } from './dto/todo-item-input.dto';import { TodoItemUpdateDTO } from './dto/todo-item-update.dto';import { TodoItemDTO } from './dto/todo-item.dto';import { TodoItemEntity } from './todo-item.entity';
@Module({  imports: [    NestjsQueryGraphQLModule.forFeature({      imports: [NestjsQueryTypeOrmModule.forFeature([TodoItemEntity])],      resolvers: [        {          DTOClass: TodoItemDTO,          EntityClass: TodoItemEntity,          CreateDTOClass: TodoItemInputDTO,          UpdateDTOClass: TodoItemUpdateDTO,          aggregate: { enabled: true }        },      ],    }),  ],})export class TodoItemModule {}

Disable Aggregate for Single Relation#

You can also selectively disable aggregates on an individual relation by specifying the enableAggregate option when defining the relation.

import { FilterableField, FilterableConnection, IDField } from '@nestjs-query/query-graphql';import { ObjectType, ID, GraphQLISODateTime, Field } from '@nestjs/graphql';import { AuthGuard } from '../../auth.guard';import { SubTaskDTO } from '../../sub-task/dto/sub-task.dto';
@ObjectType('TodoItem')@FilterableConnection('subTasks', () => SubTaskDTO, { enableAggregate: false })export class TodoItemDTO {  @IDField(() => ID)  id!: number;
  @FilterableField()  title!: string;
  @FilterableField({ nullable: true })  description?: string;
  @FilterableField()  completed!: boolean;
  @FilterableField(() => GraphQLISODateTime)  created!: Date;
  @FilterableField(() => GraphQLISODateTime)  updated!: Date;
  @Field()  age!: number;
  @FilterableField()  priority!: number;}