MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

ABC NestJS:Przewodnik dla początkujących z MongoDB (Mongoose).

Co to jest NestJS?

NestJS to nowoczesny framework NodeJS, który wykorzystuje pod maską popularne frameworki NodeJS, takie jak Express i Fastify. NestJS został w dużej mierze zainspirowany Angularem, w wyniku czego wykorzystuje system modułów w stylu Angulara. NestJS jest napisany w TypeScript, chociaż obsługuje również natywny JavaScript.

Wymagania wstępne

Aby skorzystać z tego samouczka, musisz spełnić następujące wymagania

  • Umiejętności w PostMan lub jakimkolwiek innym narzędziu do testowania API.
  • Podstawowa znajomość aplikacji NodeJS i Express.
  • Podstawowa znajomość języka TypeScript.
  • Kompetencje w MongoDB (Mongoose).

W systemie powinny być zainstalowane następujące elementy

  • NodeJS v.14 i nowsze.
  • Kod Visual Studio (zalecany) lub inne IDE.
  • PostMan lub inne narzędzie do testowania API.

Popularne terminologie używane w NestJS;

Oto niektóre z najczęściej używanych terminów w NestJS, z którymi często spotkasz się w tym artykule.

Interfejsy

Interfejs to definicja typu. W rezultacie jest używany jako kontroler typu/enforcer w funkcjach, klasach itp.

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

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

humanInterface powyżej wykonuje ścisłe sprawdzenie typu na kevin obiekt. Typescript wygeneruje błąd, jeśli dodasz inne pole lub zmienisz typ którejkolwiek z właściwości obiektu.

Kontrolery

Kontrolerzy odpowiadają za odbieranie przychodzących żądań i odpowiadanie klientowi. Kontroler współpracuje z powiązaną usługą.

Usługi

Usługa to dostawca, który przechowuje i pobiera dane i jest używany z odpowiednim kontrolerem.

Dekoratorzy

Dekorator to wyrażenie zwracające funkcję, które akceptuje target , name i property descriptor jako argumenty opcjonalne. Dekoratory są zapisywane jako @decorator-name . Zazwyczaj są one dołączone do deklaracji klas, metod i parametrów.

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

@Get dekorator powyżej oznacza blok kodu poniżej jako GET wniosek. Więcej o tym później.

Moduł

Moduł to część programu obsługująca określone zadanie. Moduł w NestJS jest oznaczony przez adnotację klasy z adnotacją @Module() dekorator. Nest używa metadanych dostarczonych przez @Module() dekorator do organizowania struktury aplikacji.

Instalowanie CLI

Aby rozpocząć, musisz zainstalować NestJS CLI ****z npm . Możesz pominąć ten krok, jeśli masz już zainstalowany NestJS CLI w swoim systemie.

npm i -g @nestjs/cli

Powyższy blok kodu zainstaluje gniazdo CLI globalnie w twoim systemie.

Tworzenie nowego projektu

Aby wygenerować nowy projekt, uruchom nest new a następnie żądaną nazwę projektu. W tym artykule napiszemy prosty interfejs API dla blogów z funkcjonalnością CRUD, przy jednoczesnym przestrzeganiu standardów RESTful.

nest new Blog-Api

To polecenie poprosi Cię o wybranie menedżera pakietów, wybierz npm .

Spowoduje to następnie utworzenie szkieletu całej struktury projektu z testowym punktem końcowym API, którego port jest ustawiony na 3000 domyślnie. Możesz to przetestować na http://localhost:3000 po uruchomieniu npm run start:dev polecenie, które uruchomi serwer w trybie czuwania podobnym do tego, co robi nodemon w ekspresowych aplikacjach.

Po przetestowaniu punktu końcowego będziesz musiał usunąć niektóre domyślne pliki, ponieważ nie będziesz ich już potrzebować. Aby to zrobić;

  • otwórz folder src i wewnątrz,
  • usuń app.controller.spec.ts ,
  • usuń app.controller.ts ,
  • usuń app.service.ts ,
  • Otwórz app.module.ts ,
  • Usuń odniesienie do AppController w controllers tablica i importy,
  • Usuń odwołanie do AppService w providers tablica i importy.

Może być również konieczna zmiana pliku README.md aby spełnić Twoje wymagania.

Twój app.module.ts plik powinien wyglądać tak,

//app.module.ts

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

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

Zmienne środowiskowe

Dobrą praktyką jest to, że niektóre poufne informacje w Twoim kodzie nie powinny być upubliczniane. Na przykład Twój PORT i Twój MongoDB URI .

Naprawmy to w kodzie.

Na twoim terminalu biegnij

npm i dotenv

Następnie utwórz plik .env w swoim katalogu i dodaj go do pliku .gitignore plik. Przechowuj swój PORT zmienna, będziesz musiał również przechowywać swój MongoDB URI później w tym samym miejscu. Teraz zastąp ujawniony PORT w swoim main.ts plik. Aby to zrobić, zaimportuj dotenv pakiet i wywołaj .config() metoda na to.

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

To powinien być Twój main.ts plik po wykonaniu powyższych kroków.

//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();

Generowanie modułów

Aby wygenerować moduł NestJS za pomocą NestJS CLI, uruchom poniższy fragment kodu.

nest generate module blogs

To polecenie tworzy blogs folder zawierający blogs.module.ts plik i rejestry BlogsModule w swoim app.module.ts plik.

Generowanie interfejsów

Wygenerujmy interfejs za pomocą NestJS CLI, aby sprawdzić typ obiektu, który będzie reprezentował Twoje posty na blogu. Aby to osiągnąć, musisz najpierw cd do blogs folder, ponieważ zaleca się, aby były przechowywane w pobliżu obiektów domeny, z którymi są skojarzone.

cd src/blogs

Następnie uruchom poniższy fragment kodu, aby wygenerować interfejs.

nest generate interface blogs

to tworzy blogs.interface.ts plik. Tutaj zdefiniujemy nasz interfejs. nazwiemy interfejs BlogsInterface .

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

przed uruchomieniem kolejnych poleceń na swoim terminalu pamiętaj o cd z src i wróć do folderu głównego, uruchamiając

cd ../..

Generowanie usług i kontrolerów

Będziesz musiał wygenerować klasę usług do przechowywania i pobierania danych oraz obsługi całej logiki i klasę kontrolera do obsługi wszystkich przychodzących żądań i wychodzących odpowiedzi.

Usługa

Aby wygenerować usługę uruchom poniższe polecenie,

nest generate service blogs

To polecenie tworzy dwa pliki blogs.service.spec.ts i blogs.service.ts i rejestruje usługę w providers tablica w blogs.module.ts .

Kontroler

Aby wygenerować kontroler, uruchom poniższe polecenie,

nest generate controller blogs

To polecenie tworzy dwa pliki blogs.controller.spec.ts i blogs.controller.ts i rejestruje kontroler w controllers tablica w blogs.module.ts .

Dzięki nim struktura Twoich blogów jest prawie kompletna, wystarczy utworzyć BlogsService dostępne dla innych części programu. Możesz to osiągnąć, tworząc exports tablica w blogs.module.ts plik i rejestracja usługi BlogsService w tej tablicy.

//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).

Zainstaluj mangusę, uruchamiając,

npm install --save @nestjs/mongoose mongoose

Po instalacji zaimportuj {MongooseModule} od '@nestjs/mongoose’ do Twojego app.module.ts plik. Następnie pobierz swój MongoDB URI i przechowuj go w swoim .env plik. Powtórz kroki, aby zaimportować dotenv w app.module.ts plik. Następnie w imports wywołanie tablicy .forRoot() metoda, która pobiera Twój MongoDB URI jako argument w MongooseModule . Podobne do mongoose.connect() w zwykłych aplikacjach ekspresowych.

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

Tworzenie schematu.

Stwórzmy schemat do zdefiniowania kształtu blogów w naszej kolekcji. Aby to zrobić,

  • Utwórz folder w swoich blogs folder, nazwij go schemas ,
  • Wewnątrz schemas folderu, utwórz plik i nazwij go blogs.schema.ts .

Następnie

Po pierwsze, musisz,

  • Importuj prop dekorator, Schema dekorator i SchemaFactory z @nestjs/mongoose ,
  • Utwórz klasę Blog i wyeksportuj go,
  • Zamień klasę w schemat, umieszczając @Schema() dekorator nad klasą,
  • Utwórz stały BlogSchema , przypisz wartość zwracaną wywołania .createForClass(Blog) z nazwą Twojej klasy jako argumentem w SchemaFactory które zaimportowałeś wcześniej.
//blogs.schema.ts

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

@Schema()
export class Blog {}

export const BlogSchema = SchemaFactory.createForClass(Blog);

Następnie musisz zdefiniować właściwości schematu.

Aby zdefiniować właściwość w schemacie, musisz oznaczyć każdą z nich za pomocą @prop() dekorator. @prop dekorator akceptuje obiekt opcji lub deklarację typu złożonego. Deklaracje typu złożonego mogą być tablicami i zagnieżdżonymi deklaracjami typu obiektu.

//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);

Następny import { Document } z 'mongoose' .

Następnie utwórz typ unii z klasą Schema i zaimportowanym Document . tak jak tak,

//blogs.schema.ts

import { Document } from 'mongoose';

export type BlogDocument = Blog & Document;

Twój końcowy blogs.schema.ts plik powinien wyglądać tak,

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);

Schemat rejestracji

Musisz zaimportować wszystko do swojego blogs.module.ts plik. Aby to osiągnąć, musisz,

  • Importuj {MongooseModule} od '@nestjs/mongoose’ ,
  • Importuj {Blog, BlogSchema} z './schemas/blogs.schema’
  • Utwórz imports tablica wewnątrz @module dekorator
  • Wywołaj .forFeature() metoda na MongooseModule . Pobiera to tablicę zawierającą obiekt, który definiuje name i schema właściwość, która powinna być ustawiona na Blog.name i Twój BlogSchema odpowiednio.
@Module({
  imports: [
    MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
  ],

Schemat wstrzykiwania

Musisz wstrzyknąć Blog modelu do blogs.service.ts za pomocą @InjectModel() dekorator. Aby to osiągnąć, musisz

  • importuj { Model } z 'mongoose' ,
  • importuj { InjectModel } z '@nestjs/mongoose’ ,
  • Importuj {Blog, BlogDocument} z './schemas/blogs.schema’ ,
  • Utwórz constructor wewnątrz BlogsService klasa,
  • Zadeklaruj private zmienną i nazwij ją blogModel i przypisz typ Model<BlogDocument> do niego. Wszystkie metody mangusty zostaną wywołane na tej zmiennej.

Przypomnij sobie, BlogDocument jest typem unii Blog klasa i Mongoose Model które stworzyłeś wcześniej. Jest używany jako typ ogólny dla Twojej zmiennej.

  • Udekoruj blogModel z @InjectModel() i przekaż Blog.name jako argument.
constructor(
    @InjectModel(Blog.name)
    private blogModel: Model<BlogDocument>,
  ) {}

Jak działa routing

Do tej pory musiałeś zauważyć, że @Controller dekorator ma ciąg 'blogs' przeszedł do niego. Oznacza to, że kontroler wyśle ​​wszystkie odpowiedzi i obsłuży wszystkie żądania wysłane na http://localhost/3000/blogs .

Następnie zaimplementujesz logikę usługi i kontrolera.

Logika serwisowa i kontrolera.

W końcu nadszedł czas na wdrożenie funkcjonalności CRUD.

Zanim zaczniemy, musisz skonfigurować kontroler. Zacznij od zaimportowania niektórych HTTP dekoratorów metod do kontrolera.

//blogs.controller.ts

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

Następnie musisz zaimportować usługę i zarejestrować ją, aby móc uzyskać do niej dostęp i zaimportować interfejs w celu sprawdzenia typu.

//blogs.controller.ts

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

Aby zarejestrować swoją usługę, utwórz constructor wewnątrz BlogsController klasę i zadeklaruj private readonly zmienna service i ustaw jego typ na BlogsService .

constructor(private readonly service: BlogsService) {}

Teraz, gdy wszystko jest gotowe, zacznijmy.

Utwórz

Logika usługi

Importuj { BlogsInterface } z './blogs.interface' i dodaj async funkcji do BlogsService klasa o nazwie createBlog , który przyjmie jeden parametr blog , którego typ to BlogInterface , a jego zwracany typ jako Promise z ogólnym <Blog> rodzaj.

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

Logika kontrolera

W swoim BlogsController klasa dodaj async funkcji do klasy. Nazwij to createBlog i oznacz go @Post dekorator, który definiuje go jako POST request.createBlog przyjmuje jeden parametr blog , którego typ to BlogInterface . Oznacz parametr za pomocą @Body dekorator, który wyodrębnia całe body obiekt z req obiektu i wypełnia parametr dekorowany wartością body .

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

Przeczytaj

Dodaj dwa async metody, jedna do zwrócenia pojedynczego posta na blogu, a druga do zwrócenia wszystkich postów na blogu.

Logika usługi

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

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

Logika kontrolera

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

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

async funkcje są oznaczone @Get dekorator, który definiuje go jako GET żądanie.

Drugi async dekorator funkcji ma argument ':id' . To właśnie przekażesz do @Param dekorator. Parametr jest oznaczony @Param('id') który wyodrębnia params właściwość z req obiektu i wypełnia parametr dekorowany wartością params .

Aktualizacja

Zaimplementujmy logikę dla PUT żądanie.

Logika usługi

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

Logika kontrolera

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

async drugi parametr funkcji jest oznaczony @Body() dekorator, który wyodrębnia całe body obiekt z req obiektu i wypełnia parametr dekorowany wartością body .

Usuń

Zaimplementujmy logikę delete prośby.

Logika usługi

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

Promise typ ogólny to void ponieważ Delete żądanie zwraca pustą obietnicę.

Logika kontrolera

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

Testowanie API

Aby przetestować ten interfejs API, powinieneś użyć narzędzia do testowania interfejsu API. W tym artykule będę używał popularnego narzędzia do testowania API o nazwie Postman. Do testowania użyję losowych danych dotyczących popularnych tematów.

Utwórz

Wykonaj POST żądanie do http://localhost/3000/blogs z następującymi obiektami JSON, spowoduje to dodanie wszystkich danych do Twojej bazy danych.

{
  "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"
}

Powinieneś otrzymać 201 odpowiedź i utworzony blog z datą i _id dodano.

Przeczytaj

Zrób GET żądanie do http://localhost/3000/blogs . Powinno to zwrócić

200 odpowiedź z tablicą wszystkich danych, które wcześniej dodałeś. Skopiuj _id właściwość jednego z obiektów tablicy.

Zrób kolejny GET żądanie do http://localhost/3000/blogs/id z wcześniej skopiowanym identyfikatorem. Powinno to zwrócić 200 odpowiedź z danymi obiektu, którego identyfikator został użyty do wysłania żądania.

Aktualizacja

Wykonaj PUT żądanie do http://localhost/3000/blogs/id z danymi poniżej. id powinien zostać zastąpiony tym, który skopiowałeś wcześniej. Powinno to zwrócić 200 odpowiedź i aktualizuje obiekt noszący id za kulisami. jeśli uruchomisz inny GET żądanie powinieneś otrzymać zaktualizowany obiekt.

{
  "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"
}

Usuń

Wykonaj DELETE żądanie do http://localhost/3000/blogs/id . Powinno to zwrócić 200 odpowiedź i usuwa obiekt noszący id za kulisami. jeśli uruchomisz inny GET żądanie, że nie zobaczysz usuniętego obiektu.

Wniosek

Więc jesteśmy w końcu na końcu tego artykułu. Podsumujmy, co omówiłeś.

  • Co to jest NestJS,
  • Terminologie w NestJS,
  • Tworzenie aplikacji NestJS,
  • Integracja MongoDB z aplikacją NestJS,
  • Manipulowanie i aplikacja NestJS,

To całkiem sporo, gratulacje, że dotarłeś tak daleko.

Możesz znaleźć kod na github.

Powodzenia w podróży z NestJS!


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Metody „statyczne” mangusty a metody „instancyjne”

  2. Wyszukiwanie rozmyte w Mongodb?

  3. Jak zacząć korzystać z ClusterControl

  4. Przegląd opcji tworzenia kopii zapasowych MongoDB

  5. Mongodb i MAMP