import { AggregateQuery , AggregateResponse , DeepPartial , DeleteManyResponse , DeleteOneOptions , Filter , FindByIdOptions , GetByIdOptions , Query , QueryService , UpdateManyResponse , UpdateOneOptions , } from '@nestjs-query/core' ; import { NotFoundException } from '@nestjs/common' ; import { Document , Model as MongooseModel , UpdateQuery } from 'mongoose' ; import { AggregateBuilder , FilterQueryBuilder } from '../query' ; import { ReferenceQueryService } from './reference-query.service' ; type MongoDBUpdatedOutput = { nModified : number ; } ; type MongoDBDeletedOutput = { deletedCount : number ; } ; example QueryService InjectModel export class MongooseQueryService < Entity extends Document > extends ReferenceQueryService < Entity > implements QueryService < Entity , DeepPartial < Entity > , DeepPartial < Entity > > { constructor ( readonly Model , readonly filterQueryBuilder = new FilterQueryBuilder ( Model ) ) { super ( ) ; } example param query async query ( query ) { const { filterQuery , options } = this . filterQueryBuilder . buildQuery ( query ) ; return this . Model . find ( filterQuery , { } , options ) . exec ( ) ; } async aggregate ( filter , aggregateQuery ) { const { aggregate , filterQuery , options } = this . filterQueryBuilder . buildAggregateQuery ( aggregateQuery , filter ) ; const aggPipeline = [ { $match : filterQuery } , { $group : aggregate } ] ; if ( options . sort ) { aggPipeline . push ( { $sort : options . sort ?? { } } ) ; } const aggResult = ( await this . Model . aggregate < Record < string , unknown > > ( aggPipeline ) . exec ( ) ) as Record < string , unknown > [ ] ; return AggregateBuilder . convertToAggregateResponse ( aggResult ) ; } count ( filter ) { const filterQuery = this . filterQueryBuilder . buildFilterQuery ( filter ) ; return this . Model . count ( filterQuery ) . exec ( ) ; } example param id param opts async findById ( id , opts ? ) { const filterQuery = this . filterQueryBuilder . buildIdFilterQuery ( id , opts ?. filter ) ; const doc = await this . Model . findOne ( filterQuery ) ; if ( ! doc ) { return undefined ; } return doc ; } example param id param opts async getById ( id , opts ? ) { const doc = await this . findById ( id , opts ) ; if ( ! doc ) { throw new NotFoundException ( `Unable to find ${ this . Model . modelName } with id: ${ id }` ) ; } return doc ; } example param record async createOne ( record ) { this . ensureIdIsNotPresent ( record ) ; return this . Model . create ( record ) ; } example param records async createMany ( records ) { records . forEach ( ( r ) => this . ensureIdIsNotPresent ( r ) ) ; return this . Model . create ( records ) ; } example param id param update param opts async updateOne ( id , update , opts ? ) { this . ensureIdIsNotPresent ( update ) ; const filterQuery = this . filterQueryBuilder . buildIdFilterQuery ( id , opts ?. filter ) ; const doc = await this . Model . findOneAndUpdate ( filterQuery , this . getUpdateQuery ( update ) , { new : true , } ) ; if ( ! doc ) { throw new NotFoundException ( `Unable to find ${ this . Model . modelName } with id: ${ id }` ) ; } return doc ; } example param update param filter async updateMany ( update , filter ) { this . ensureIdIsNotPresent ( update ) ; const filterQuery = this . filterQueryBuilder . buildFilterQuery ( filter ) ; const res = ( await this . Model . updateMany ( filterQuery , this . getUpdateQuery ( update ) ) . exec ( ) ) as MongoDBUpdatedOutput ; return { updatedCount : res . nModified || 0 } ; } example param id param opts async deleteOne ( id , opts ? ) { const filterQuery = this . filterQueryBuilder . buildIdFilterQuery ( id , opts ?. filter ) ; const doc = await this . Model . findOneAndDelete ( filterQuery ) ; if ( ! doc ) { throw new NotFoundException ( `Unable to find ${ this . Model . modelName } with id: ${ id }` ) ; } return doc ; } example param filter async deleteMany ( filter ) { const filterQuery = this . filterQueryBuilder . buildFilterQuery ( filter ) ; const res = ( await this . Model . deleteMany ( filterQuery ) . exec ( ) ) as MongoDBDeletedOutput ; return { deletedCount : res . deletedCount || 0 } ; } private ensureIdIsNotPresent ( e ) { if ( Object . keys ( e ) . find ( ( f ) => f === 'id' || f === '_id' ) ) { throw new Error ( 'Id cannot be specified when updating or creating' ) ; } } private getUpdateQuery ( entity ) { if ( entity instanceof this . Model ) { return entity . modifiedPaths ( ) . reduce ( ( update , k ) => ( { ... update , [ k ] : entity . get ( k ) } ) , { } ) ; } return entity as UpdateQuery < Entity > ; } }