add elastic search
This commit is contained in:
@@ -1,4 +1,16 @@
|
||||
import {Controller, Get, Post, Body, Patch, Param, Delete, UseGuards, Req} from '@nestjs/common';
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
UseGuards,
|
||||
Req,
|
||||
Query,
|
||||
ClassSerializerInterceptor, UseInterceptors
|
||||
} from '@nestjs/common';
|
||||
import {PostsService} from './posts.service';
|
||||
import {CreatePostDto} from './dto/create-post.dto';
|
||||
import {UpdatePostDto} from './dto/update-post.dto';
|
||||
@@ -6,6 +18,7 @@ import JwtAuthenticationGuard from "../authentication/jwt-authentication.guard";
|
||||
import RequestWithUser from "../authentication/requestWithUser.interface";
|
||||
|
||||
@Controller('posts')
|
||||
@UseInterceptors(ClassSerializerInterceptor)
|
||||
export class PostsController {
|
||||
constructor(private readonly postsService: PostsService) {
|
||||
}
|
||||
@@ -16,6 +29,15 @@ export class PostsController {
|
||||
return this.postsService.createPost(post, req.user);
|
||||
}
|
||||
|
||||
|
||||
@Get()
|
||||
async getPosts(@Query('search') search: string) {
|
||||
if (search) {
|
||||
return this.postsService.searchForPosts(search);
|
||||
}
|
||||
return this.postsService.getAllPosts();
|
||||
}
|
||||
|
||||
@Get()
|
||||
findAll() {
|
||||
return this.postsService.findAll();
|
||||
|
||||
@@ -6,12 +6,15 @@ import {InjectRepository} from "@nestjs/typeorm";
|
||||
import {Repository} from "typeorm";
|
||||
import Post from './entities/post.entity';
|
||||
import {PostNotFoundException} from "./exception/postNotFound.exception";
|
||||
import PostsSearchService from "./postsSearch.service";
|
||||
import {In} from "typeorm";
|
||||
|
||||
@Injectable()
|
||||
export class PostsService {
|
||||
|
||||
constructor(
|
||||
@InjectRepository(Post) private repo: Repository<Post>,
|
||||
private postsSearchService: PostsSearchService
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -24,6 +27,19 @@ export class PostsService {
|
||||
return newPost;
|
||||
}
|
||||
|
||||
async searchForPosts(text: string) {
|
||||
const results = await this.postsSearchService.search(text);
|
||||
const ids = results.flatMap(result => result.hits.hits.map(hit => hit._source.id));
|
||||
if (!ids.length) {
|
||||
return [];
|
||||
}
|
||||
return this.repo
|
||||
.find({
|
||||
where: {id: In(ids)}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
getAllPosts() {
|
||||
return this.repo.find({relations: ['author']});
|
||||
@@ -64,11 +80,26 @@ export class PostsService {
|
||||
return `This action returns a #${id} post`;
|
||||
}
|
||||
|
||||
update(id: number, updatePostDto: UpdatePostDto) {
|
||||
return `This action updates a #${id} post`;
|
||||
async update(id: number, post: UpdatePostDto) {
|
||||
await this.repo.update(id, post);
|
||||
const updatedPost = await this.repo.findOne({
|
||||
where: {id},
|
||||
relations: {
|
||||
author: true,
|
||||
}
|
||||
});
|
||||
if (updatedPost) {
|
||||
await this.postsSearchService.update(updatedPost);
|
||||
return updatedPost;
|
||||
}
|
||||
throw new PostNotFoundException(id);
|
||||
}
|
||||
|
||||
remove(id: number) {
|
||||
return `This action removes a #${id} post`;
|
||||
async remove(id: number) {
|
||||
const deleteResponse = await this.repo.delete(id);
|
||||
if (!deleteResponse.affected) {
|
||||
throw new PostNotFoundException(id);
|
||||
}
|
||||
await this.postsSearchService.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,81 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ElasticsearchService } from '@nestjs/elasticsearch';
|
||||
import {Injectable} from '@nestjs/common';
|
||||
import {ElasticsearchService} from '@nestjs/elasticsearch';
|
||||
import Post from "./entities/post.entity";
|
||||
import {PostSearchResult} from "./types/postSearchResult.interface";
|
||||
import {PostSearchBody} from "./types/postSearchBody.interface";
|
||||
|
||||
@Injectable()
|
||||
export default class PostsSearchService {
|
||||
index = 'posts'
|
||||
index = 'posts';
|
||||
|
||||
constructor(
|
||||
private readonly elasticsearchService: ElasticsearchService
|
||||
) {}
|
||||
constructor(
|
||||
private readonly elasticsearchService: ElasticsearchService
|
||||
) {
|
||||
}
|
||||
|
||||
async indexPost(post: Post) {
|
||||
return this.elasticsearchService.index<PostSearchBody>({
|
||||
index: this.index,
|
||||
body: {
|
||||
id: post.id,
|
||||
title: post.title,
|
||||
content: post.content,
|
||||
authorId: post.author.id
|
||||
}
|
||||
})
|
||||
}
|
||||
async indexPost(post: Post) {
|
||||
return this.elasticsearchService.index<PostSearchBody>({
|
||||
index: this.index,
|
||||
document: {
|
||||
id: post.id,
|
||||
title: post.title,
|
||||
content: post.content,
|
||||
authorId: post.author.id
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async search(text: string) {
|
||||
const result = await this.elasticsearchService.search<PostSearchResult>({
|
||||
index: this.index,
|
||||
query: {
|
||||
multi_match: {
|
||||
query: text,
|
||||
fields: ['title', 'content'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const hits = result.hits.hits;
|
||||
return hits.map((item) => item._source);
|
||||
}
|
||||
|
||||
|
||||
async remove(postId: number) {
|
||||
await this.elasticsearchService.deleteByQuery({
|
||||
index: this.index,
|
||||
query: {
|
||||
match: {
|
||||
id: postId,
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
async update(post: Post) {
|
||||
const newBody: PostSearchBody = {
|
||||
id: post.id,
|
||||
title: post.title,
|
||||
content: post.content,
|
||||
authorId: post.author.id
|
||||
};
|
||||
|
||||
const script = Object.entries(newBody).reduce((result, [key, value]) => {
|
||||
return `${result} ctx._source.${key}='${value}';`;
|
||||
}, '');
|
||||
|
||||
await this.elasticsearchService.updateByQuery({
|
||||
index: this.index,
|
||||
query: {
|
||||
match: {
|
||||
id: post.id,
|
||||
}
|
||||
},
|
||||
script: {
|
||||
source: script
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async search(text: string) {
|
||||
const response = await this.elasticsearchService.search<PostSearchResult>({
|
||||
index: this.index,
|
||||
body: {
|
||||
query: {
|
||||
multi_match: {
|
||||
query: text,
|
||||
fields: ['title', 'content']
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
const hits = body.hits.hits;
|
||||
return hits.map((item) => item._source);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import {PostSearchBody} from "./postSearchBody.interface";
|
||||
|
||||
export interface PostSearchResult {
|
||||
hits: {
|
||||
|
||||
Reference in New Issue
Block a user