Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save programmerShinobi/438eac64bc2ec61c7be6c1c1cb59ad70 to your computer and use it in GitHub Desktop.
Save programmerShinobi/438eac64bc2ec61c7be6c1c1cb59ad70 to your computer and use it in GitHub Desktop.
How to use elasticsearch in NestJS Framework
  1. Edit package.json
    {
      ...
      "dependencies": {
        "@nestjs/bull": "^10.0.1",
        "@nestjs/common": "^10.3.0",
        "@nestjs/config": "^3.1.1",
        "@nestjs/core": "^10.3.0",
        "@nestjs/elasticsearch": "^10.0.1",
        "@elastic/elasticsearch": "^8.11.0",
      },
      "devDependencies": {
        "@nestjs/cli": "^10.2.1",
        "@nestjs/schematics": "^10.0.3",
        "@nestjs/testing": "^10.2.10",
        "@types/express": "^4.17.13",
        "@types/jest": "27.4.1",
        "@types/node": "^16.0.0"
      },
      ...
    }
  2. Install all dependencies & devDependencies in package.json
    $ yarn install
  3. Create .env
    ELASTIC_HOST=Your_Elastic_Host_Is_Actived
  4. Edit app.module.ts
    import { Module } from '@nestjs/common';
    import {
      ElasticsearchModule,
      ElasticsearchModuleAsyncOptions,
    } from '@nestjs/elasticsearch';
    import { ConfigModule, ConfigService } from '@nestjs/config';
    import { AppController } from './app.controller';
    import { AppService } from './app.service';
    
    const ElasticOptions: ElasticsearchModuleAsyncOptions = {
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => {
        console.log('[Elastic] Host: ', config.get<string>('ELASTIC_HOST'));
        console.log('[Elastic] Host process: ', process.env.ELASTIC_HOST);
        return {
          node: config.get<string>('ELASTIC_HOST'),
        };
      },
    };
    
    @Module({
      imports: [
        ElasticsearchModule.registerAsync(ElasticOptions),
      ],
      controllers: [AppController],
      providers: [AppService]
    })
    export class AppModule {}
  5. Create indices-properties.dto.ts
    import { IsNotEmpty, IsString, IsNumber } from 'class-validator';
    
    export class IndicesPropertiesDto {
      @IsNotEmpty()
      @IsString()
      name: string;
    
      @IsNotEmpty()
      @IsNumber()
      age: string;
    
      @IsNotEmpty()
      hobby: string[];
    }
  6. Edit app.service.ts
    import {
      Inject,
      Injectable,
    } from '@nestjs/common';
    import { ElasticsearchService } from '@nestjs/elasticsearch';
    import {
      IndicesCreateResponse,
      WriteResponseBase,
    } from '@elastic/elasticsearch/lib/api/types';
    import { IndicesPropertiesDto } './indices-properties.dto';
    
    @Injectable()
    export class AppService {
    
      constructor(
        private readonly client: ElasticsearchService,
      ) {
        super(AppService?.name);
      }
    
      private async createIndicesInElastic(
        index: string
      ): Promise<this> {
        try {
          const createIndices = 
            await this.client.indices.create({
              index,
              body: {
                mappings: {
                  // set field types
                  properties: {
                    name: { type: 'string' },
                    age: { type: 'number' },
                    hobby: { type: 'text' }
                  },
                },
              },
            });
          if(!createIndices) throw new BadRequestException('create indices failed!');
          console.log(createIndices);
    
          await this.client.indices.refresh({
            index,
          });
    
          return this;
        } catch(error) {
          console.error(error?.response);
          throw new BadRequestException(error?.response);
        }
    
      async createAndAddIndexInIndicesElastic(
        dto: IndicesPropertiesDto
      ): Promise<WriteResponseBase> {
        try {
          const index = 'set-your-index';
    
          await this.createIndicesInElastic(index);
    
          const body: IndicesPropertiesDto = dto;
          const result: WriteResponseBase = 
            await this.client.index({
              index,
              body
            });
          if(!result) throw new BadRequestException(
            'add index in indices elastic failed!'
          );
    
          console.log(result);
          return result;
        } catch(error) {
          console.error(error?.response);
          throw new BadRequestException(error?.response);
        }
      }
    
      async deleteIndicesByIndex(index: string): Promise<IndicesResponseBase> {
        try {
          await this.client.indices.clearCache({
            index,
            fielddata: true,
            query: true,
            request: true,
          });
    
          const result: IndicesResponseBase = 
            await this.client.indices.delete({
              index
            });
    
          if (!result) throw new BadRequestException('Invalid Parameters');
    
          return result;
        } catch (error) {
          this.logger.error(error?.response);
          throw new BadRequestException(error?.response);
        }
      }
    }
  7. Edit app.controller.ts
    import { 
      Res,
      Req,
      Body,
      Param,
      Delete,
      Controller,
      BadRequestException
    } from '@nestjs/common';
    import { Request, Response } from 'express';
    import { AppService } from './app.service';
    import { IndicesPropertiesDto } './indices-properties.dto';
    
    @Controller({
      version: '1',
      path: 'your-path'
    })
    
    export class AppController {
      constructor(private readonly appService: AppService) {
        super(AppController.name)
      }
    
      @Post()
      async createAndAddIndexInElastic<T>(
        @Body dto: IndicesPropertiesDto;
        @Res() res: Response,
      ): Promise<Response<T, Record<string, T>>> {
        try {
          const data = this.appService.createAndAddIndexInIndicesElastic(dto);
          if(!data) throw new BadRequestException('Data failed to create & add index in elasticsearch');
    
          const result = {
            data,
            meta: {
              status: 'OK',
            message: 'Data has been saved',
            time: new Date(),
          }
          return res.status(201).json(result);
        } catch(error) {
          return res.status(400).json(error?.response);
        }
      }
    
      @Delete()
      async deleteIndicesByIndex<T>(
        @Param('index') index: string,
        @Req() req: Request,
        @Res() res: Response,
      ): Promise<Response<T, Record<string, T>>> {
        try {
          if (!indexName)
            throw new BadRequestException('index not found in parameters');
          await this.appService.deleteIndicesByIndex(index);
          return res.status(204).send();
        } catch (error) {
          return res.status(400).json(error?.response);
        }
      }
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment