MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

ABCs на NestJS:Ръководство за начинаещи с MongoDB (Mongoose).

Какво е NestJS?

NestJS е модерна NodeJS рамка, която използва популярни NodeJS рамки като Express и Fastify под капака. NestJS до голяма степен е вдъхновен от Angular и в резултат на това използва модулна система в стил Angular. NestJS е написан на TypeScript, въпреки че поддържа и собствен JavaScript.

Предпоставки

За да следвате този урок, трябва да отговаряте на следните изисквания

  • Компетентност в PostMan или друг инструмент за тестване на API.
  • Основни познания за приложенията NodeJS и Express.
  • Основни познания за TypeScript.
  • Компетентност в MongoDB(Mongoose).

Следното трябва да бъде инсталирано на вашата система

  • NodeJS v.14 и по-нова версия.
  • Код на Visual Studio (препоръчително) или всяка друга IDE.
  • PostMan или друг инструмент за тестване на API.

Общи терминологии, използвани в NestJS;

Ето някои от най-често използваните термини в NestJS, които ще срещнете много в тази статия.

Интерфейси

Интерфейсът е дефиниция на тип. В резултат на това той се използва като средство за проверка/прилагане на типа във функции, класове и т.н.

interface humanInterface{
  name:string;
  gender:string;
  age:number;
}

const kevin: humanInterface={
  name:'Kevin Sunders',
  gender:'Male',
  age: 25,
}

humanInterface по-горе извършва строга проверка на типа на kevin обект. Typescript ще изведе грешка, ако добавите друго поле или промените типа на някое от свойствата на обекта.

Контролери

Контролерите отговарят за получаването на входящи заявки и отговарянето на клиента. Контролерът си сътрудничи със свързаната с него услуга.

Услуги

Услугата е доставчик, който съхранява и извлича данни и се използва със съответния контролер.

Декоратори

Декораторът е връщащ функция израз, който приема target , name и property descriptor като незадължителни аргументи. Декораторите се записват като @decorator-name . Те обикновено са прикрепени към декларации на клас, методи и параметри.

@Get()
   getAll(): Model[] {
    return this.testService.getAll();
  }

@Get декораторът отгоре маркира кодовия блок под него като GET искане. Повече за това по-късно.

Модул

Модулът е част от програма, която се справя с определена задача. Модул в NestJS се маркира чрез анотиране на клас, анотиран с @Module() декоратор. Nest използва метаданните, предоставени от @Module() декоратор за организиране на структурата на приложението.

Инсталиране на CLI

За да започнете, ще трябва да инсталирате NestJS CLI **** с npm . Можете да пропуснете тази стъпка, ако вече имате инсталиран NestJS CLI във вашата система.

npm i -g @nestjs/cli

Този кодов блок по-горе ще инсталира гнездовия CLI глобално във вашата система.

Създаване на нов проект

За да генерирате нов проект, стартирайте nest new последвано от желаното от вас име на проект. За тази статия ще напишем прост API за блог с функционалност CRUD, като същевременно се придържаме към стандартите RESTful.

nest new Blog-Api

Тази команда ще ви подкани да изберете мениджър на пакети, изберете npm .

Това след това ще обедини цялата структура на проекта с тестова крайна точка на API, чийто порт е настроен на 3000 по подразбиране. Можете да го тествате на http://localhost:3000 след стартиране на npm run start:dev команда, която ще стартира сървъра в режим на гледане, подобно на това, което nodemon прави в експресните приложения.

След като тествате крайната точка, ще трябва да изтриете някои от файловете по подразбиране, защото вече няма да имате нужда от тях. За да направите това;

  • отворете папката src и вътре,
  • изтрийте app.controller.spec.ts ,
  • изтрийте app.controller.ts ,
  • изтрийте app.service.ts ,
  • Отворете app.module.ts ,
  • Премахнете препратката към AppController в controllers масив и импортирания,
  • Премахнете препратката към AppService в providers масив и импортирания.

Може също да се наложи да промените README.md за да отговаря на вашите спецификации.

Вашият app.module.ts файлът трябва да изглежда така,

//app.module.ts

import { Module } from '@nestjs/common';

@Module({
  imports: [],
  controllers: [],
  providers: [],
})
export class AppModule {}

Променливи на околната среда

Като добра практика, част от чувствителната информация във вашия код не трябва да се оповестява публично. Например вашият PORT и вашия MongoDB URI .

Нека поправим това във вашия код.

На вашия терминал стартирайте

npm i dotenv

След това създайте .env файл във вашата директория и го добавете към вашия .gitignore файл. Съхранявайте вашия PORT променлива, ще трябва да съхраните и вашия MongoDB URI по-късно на същото място. Сега сменете открития PORT във вашия main.ts файл. За да направите това, импортирайте dotenv пакет и извикайте .config() метод върху него.

import * as dotenv from 'dotenv';
dotenv.config();

Това трябва да е вашият main.ts файл, след като изпълните стъпките по-горе.

//main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as dotenv from 'dotenv';
dotenv.config();

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(process.env.PORT);
}
bootstrap();

Генериране на модули

За да генерирате NestJS модул с помощта на NestJS CLI, изпълнете кодовия фрагмент по-долу.

nest generate module blogs

Тази команда създава blogs папка, която съдържа blogs.module.ts файл и регистри BlogsModule във вашия app.module.ts файл.

Генериране на интерфейси

Нека генерираме интерфейс, използвайки NestJS CLI, за да извършим проверка на типа за обекта, който ще представлява публикациите ви в блога. За да постигнете това, първо трябва да cd в blogs папка, защото се препоръчва те да се съхраняват близо до обектите на домейна, към които са свързани.

cd src/blogs

След това стартирайте кодовия фрагмент по-долу, за да генерирате интерфейса.

nest generate interface blogs

това създава blogs.interface.ts файл. Тук ще дефинираме нашия интерфейс. ще наречем интерфейса BlogsInterface .

export interface BlogsInterface {
  title: string;
  body: string;
  category: string;
  dateCreated: Date;
}

преди да изпълните повече команди на вашия терминал, не забравяйте да cd извън src папка и обратно във вашата основна папка, като стартирате

cd ../..

Генериране на услуги и контролери

Ще трябва да генерирате сервизен клас за съхраняване и извличане на данни и за обработка на цялата логика и клас на контролер за обработка на всички входящи заявки и изходящи отговори.

Услуга

За да генерирате услуга, изпълнете командата по-долу,

nest generate service blogs

Тази команда създава два файла blogs.service.spec.ts и blogs.service.ts и регистрира услугата в providers масив в blogs.module.ts .

Контролер

За да генерирате контролер, изпълнете командата по-долу,

nest generate controller blogs

Тази команда създава два файла blogs.controller.spec.ts и blogs.controller.ts и регистрира контролера в controllers масив в blogs.module.ts .

С тях структурата на вашите блогове е почти завършена, просто трябва да направите BlogsService достъпни за други части на вашата програма. Можете да постигнете това, като създадете exports масив в blogs.module.ts файл и регистриране на BlogsService в този масив.

//blogs.module.ts

import { Module } from '@nestjs/common';
import { BlogsService } from './blogs.service';
import { BlogsController } from './blogs.controller';

@Module({
  providers: [BlogsService],
  controllers: [BlogsController],
  exports: [BlogsService],
})
export class BlogsModule {}

MongoDB(Mongoose).

Инсталирайте mongoose, като стартирате,

npm install --save @nestjs/mongoose mongoose

След инсталацията импортирайте {MongooseModule} от '@nestjs/mongoose’ във вашия app.module.ts файл. След това вземете вашия MongoDB URI и го съхранявайте във вашия .env файл. Повторете стъпките за импортиране на dotenv в app.module.ts файл. След това в imports извикване на масив .forRoot() метод, който взема вашия MongoDB URI като аргумент на MongooseModule . Подобно на mongoose.connect() в обикновени експресни приложения.

@Module({
  imports: [BlogsModule, MongooseModule.forRoot(process.env.MONGODB_URI)],

Създаване на схема.

Нека създадем схема, за да дефинираме формата на блоговете в нашата колекция. За да направите това,

  • Създайте папка във вашите blogs папка, наименувайте я schemas ,
  • Вътре в schemas папка, създайте файл и го наречете blogs.schema.ts .

След това,

Първо, ще трябва,

  • Импортирайте prop декоратор, Schema декоратор и SchemaFactory от @nestjs/mongoose ,
  • Създайте клас Blog и го експортирайте,
  • Превърнете класа в схема, като поставите @Schema() декоратор над класа,
  • Създайте константа BlogSchema , присвоете връщаната стойност за извикване на .createForClass(Blog) с името на вашия клас като аргумент на SchemaFactory които сте импортирали по-рано.
//blogs.schema.ts

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';

@Schema()
export class Blog {}

export const BlogSchema = SchemaFactory.createForClass(Blog);

След това ще трябва да дефинирате свойствата на схемата.

За да дефинирате свойство в схемата, ще трябва да маркирате всяко от тях с @prop() декоратор. @prop декораторът приема обект с опции или декларация за сложен тип. Декларациите за сложни типове могат да бъдат масиви и вложени декларации за тип обекти.

//blogs.schema.ts

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';

@Schema()
export class Blog {
  @Prop({ required: true })
  title: string;

  @Prop({ required: true })
  body: string;

  @Prop({ required: true })
  category: string;

  @Prop({ required: true })
  dateCreated: Date;
}

export const BlogSchema = SchemaFactory.createForClass(Blog);

Следващ импорт { Document } от 'mongoose' .

След това създайте тип на обединение с класа Schema и импортирания Document . Така,

//blogs.schema.ts

import { Document } from 'mongoose';

export type BlogDocument = Blog & Document;

Вашият окончателен blogs.schema.ts файлът трябва да изглежда така,

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type BlogDocument = Blog & Document;

@Schema()
export class Blog {
  @Prop({ required: true })
  title: string;

  @Prop({ required: true })
  body: string;

  @Prop({ required: true })
  category: string;

  @Prop({ required: true })
  dateCreated: Date;
}

export const BlogSchema = SchemaFactory.createForClass(Blog);

Схема за регистриране

Ще трябва да импортирате всичко във вашия blogs.module.ts файл. За да постигнете това, ще трябва да,

  • Импортиране на {MongooseModule} от '@nestjs/mongoose’ ,
  • Импортиране на {Blog, BlogSchema} от './schemas/blogs.schema’
  • Създайте imports масив вътре в @module декоратор
  • Извикайте .forFeature() метод на MongooseModule . Това включва масив, съдържащ обект, който дефинира name и schema свойство, което трябва да бъде зададено на вашия Blog.name и вашата BlogSchema съответно.
@Module({
  imports: [
    MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
  ],

Схема за инжектиране

Ще трябва да инжектирате Blog модел в blogs.service.ts с помощта на @InjectModel() декоратор. За да постигнете това, ще трябва да

  • import { Model } от 'mongoose' ,
  • import { InjectModel } от '@nestjs/mongoose’ ,
  • Импортиране на {Blog, BlogDocument} от './schemas/blogs.schema’ ,
  • Създайте constructor вътре в BlogsService клас,
  • Обявете private променлива и я наречете blogModel и задайте тип Model<BlogDocument> към него. Всички методи на mongoose ще бъдат извикани на тази променлива.

Припомнете си това, BlogDocument е типът на съюза на Blog клас и Mongoose Model които сте създали по-рано. Използва се като общ тип за вашата променлива.

  • Украсете blogModel с @InjectModel() и предайте Blog.name като аргумент.
constructor(
    @InjectModel(Blog.name)
    private blogModel: Model<BlogDocument>,
  ) {}

Как работи маршрутизирането

Досега сигурно сте забелязали, че @Controller декораторът има низ 'blogs' премина в него. Това означава, че контролерът ще изпраща всички отговори и ще обработва всички заявки, направени на http://localhost/3000/blogs .

След това ще внедрите логиката на услугата и контролера.

Логика на услугата и контролера.

Най-накрая е време да внедрите своята CRUD функционалност.

Преди да започнем, ще трябва да настроите своя контролер. Започнете с импортиране на някакъв HTTP декоратори на метод във вашия контролер.

//blogs.controller.ts

import {
  Controller,
  Body,
  Delete,
  Get,
  Post,
  Put,
  Param,
} from '@nestjs/common';

След това ще трябва да импортирате услугата и да я регистрирате, за да можете да получите достъп до нея и да импортирате интерфейса за проверка на типа.

//blogs.controller.ts

import { BlogsInterface } from './blogs.interface';
import { BlogsService } from './blogs.service';

За да регистрирате услугата си, създайте constructor вътре в BlogsController клас и декларирайте private readonly променлива service и задайте типа му на BlogsService .

constructor(private readonly service: BlogsService) {}

Сега, когато сте готови, нека да започнем.

Създаване

Сервизна логика

Импортирайте { BlogsInterface } от './blogs.interface' и добавете async функция към BlogsService клас, наречен createBlog , което ще приеме един параметър blog , с неговия тип като BlogInterface , и неговия тип връщане като Promise с общ <Blog> Тип.

async createBlog(blog: BlogsInterface): Promise<Blog> {
    return await new this.blogModel({
      ...blog,
      dateCreated: new Date(),
    }).save();
  }

Логика на контролера

Във вашия BlogsController клас добавете async функция към класа. Наречете го createBlog и го маркирайте с @Post декоратор, който го дефинира като POST заявка.createBlog приема един параметър blog , с неговия тип като BlogInterface . Маркирайте параметъра с @Body декоратор, който извлича цялото body обект от req обект и попълва декорирания параметър със стойността на body .

@Post()
  async createBlog(
    @Body()
    blog: BlogsInterface,
  ) {
    return await this.service.createBlog(blog);
  }

Прочетете

Добавете две async методи, Единият за връщане на една публикация в блога, а вторият за връщане на всички публикации в блога.

Сервизна логика

async getAllBlogs(): Promise<Blog[]> {
    return await this.blogModel.find().exec();
  }

  async getBlog(id: string): Promise<Blog> {
    return await this.blogModel.findById(id);
  }

Логика на контролера

  @Get()
  async getAllBlogs() {
    return await this.service.getAllBlogs();
  }

  @Get(':id')
  async getBlog(@Param('id') id: string) {
    return await this.service.getBlog(id);
  }

async функциите са маркирани с @Get декоратор, който го дефинира като GET заявка.

Вторият async декораторът на функцията има аргумент ':id' . Което ще предадете в @Param декоратор. Параметърът е маркиран с @Param('id') който извлича params свойство от req обект и попълва декорирания параметър със стойността на params .

Актуализация

Нека приложим логиката за PUT заявка.

Сервизна логика

async updateBlog(id: string, body: BlogsInterface): Promise<Blog> {
    return await this.blogModel.findByIdAndUpdate(id, body);
  }

Логика на контролера

@Put(':id')
  async updateBlog(
    @Param('id')
    id: string,
    @Body()
    blog: BlogsInterface,
  ) {
    return await this.service.updateBlog(id, blog);
  } 

async Вторият параметър на функцията е маркиран с @Body() декоратор, който извлича цялото body обект от req обект и попълва декорирания параметър със стойността на body .

Изтриване

Нека приложим логиката за delete заявки.

Сервизна логика

async deleteBlog(id: string): Promise<void> {
    return await this.blogModel.findByIdAndDelete(id);
  }

Promise генеричният тип е void защото Delete request връща празно обещание.

Логика на контролера

@Delete(':id')
  async deleteBlog(@Param('id') id: string) {
    return await this.service.deleteBlog(id);
  }

Тестване на API

За да тествате този API, трябва да използвате инструмент за тестване на API. За тази статия ще използвам популярен инструмент за тестване на API, наречен Postman. Ще използвам произволни данни за популярни теми за тестване.

Създаване

Направете POST заявка до http://localhost/3000/blogs със следните JSON обекти, това ще добави всички данни към вашата база данни.

{
  "title": "jeen-yuhs",
  "body": "The life of superstar rapper Kanye West is currently streaming on Netflix - and according to our jeen-yuhs review, it's a fascinating watch. -credit:Radio Times",
  "category":"Music"
}

{
  "title": "Why You Should Always Wash Your Hands",
  "body": "Germs from unwashed hands can be transferred to other objects, like handrails, tabletops, or toys, and then transferred to another person's hands.-credit cdc.gov",
  "category":"Health"
}

{
  "title": "Why You Should Follow me on Twitter",
  "body": "Well, Because I asked nicely",
  "category":"Random"
}

Трябва да получите 201 отговор и създадения блог с дата и _id добавено.

Прочетете

Направете GET заявка до http://localhost/3000/blogs . Това трябва да върне a

200 отговор с масив от всички данни, които сте добавили по-рано. Копирайте _id свойство на един от обектите на масива.

Направете друг GET заявка до http://localhost/3000/blogs/id с копирания по-рано идент. Това трябва да върне 200 отговор с данните на обекта, чийто идентификатор е използван за подаване на заявката.

Актуализация

Направете PUT заявка до http://localhost/3000/blogs/id с данните по-долу. id трябва да бъде заменен с този, който сте копирали по-рано. Това трябва да върне 200 отговор и актуализира обекта, носещ id зад сцената. ако стартирате друг GET заявка трябва да получите актуализирания обект.

{
  "title": "why you Should Cut your Nails",
  "body": "It's important to trim your nails regularly. Nail trimming together with manicures makes your nails look well-groomed, neat, and tidy.- credit:WebMD",
  "category":"Health"
}

Изтриване

Направете DELETE заявка до http://localhost/3000/blogs/id .Това трябва да върне 200 отговор и изтрива обекта, носещ id зад сцената. ако стартирате друг GET поиска, няма да видите изтрития обект.

Заключение

Така че най-накрая сме в края на тази статия. Нека обобщим това, което сте обхванали.

  • Какво е NestJS,
  • Терминологии в NestJS,
  • Създаване на приложение NestJS,
  • Интегриране на MongoDB в приложение NestJS,
  • Манипулиране и приложение NestJS,

Това е доста, поздравления, че стигнахте дотук.

Можете да намерите кода на github.

Успех на вашето NestJS пътуване!


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Опцията useFindAndModify не се поддържа

  2. Как да актуализирате съществуващи документи в MongoDB

  3. Набори реплики на MongoDB с арбитри

  4. mongodb премества документи от една колекция в друга колекция

  5. MongoDB - Филтриране на съдържанието на вътрешен масив в набор от резултати