sql >> データベース >  >> NoSQL >> MongoDB

NestJSのABC:MongoDB(Mongoose)の初心者向けガイド。

    NestJSとは何ですか?

    NestJSは、ExpressやFastifyなどの一般的なNodeJSフレームワークを内部で利用する最新のNodeJSフレームワークです。 NestJSは主にAngularに触発され、その結果、Angularスタイルのモジュールシステムを採用しています。 NestJSはTypeScriptで記述されていますが、ネイティブJavaScriptもサポートしています。

    前提条件

    このチュートリアルに従うには、次の要件を満たす必要があります

    • PostManまたはその他のAPIテストツールの能力。
    • NodeJSおよびExpressアプリの基本的な知識。
    • TypeScriptの基本的な知識。
    • MongoDB(Mongoose)の能力。

    以下をシステムにインストールする必要があります

    • NodeJSv.14以降。
    • Visual Studio Code(推奨)またはその他の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のインストール

    開始するには、npmを使用してNestJSCLIをインストールする必要があります**** 。システムにNestJSCLIがすでにインストールされている場合は、この手順をスキップできます。

    npm i -g @nestjs/cli
    

    上記のコードブロックは、ネストCLIをシステムにグローバルにインストールします。

    新しいプロジェクトの作成

    新しいプロジェクトを生成するには、nest newを実行します 希望するプロジェクト名が続きます。この記事では、RESTful標準に準拠しながら、CRUD機能を備えたシンプルなブログAPIを作成します。

    nest new Blog-Api
    

    このコマンドは、パッケージマネージャーを選択するように求めるプロンプトを表示します。npmを選択します。 。

    これにより、ポートが3000に設定されているテストAPIエンドポイントを使用して、プロジェクト構造全体がスキャフォールディングされます。 デフォルトでは。 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 CLIを使用してNestJSモジュールを生成するには、以下のコードスニペットを実行します。

    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に2つのファイルを作成します およびblogs.service.ts providersにサービスを登録します blogs.module.tsの配列 。

    コントローラー

    コントローラを生成するには、以下のコマンドを実行します。

    nest generate controller blogs
    

    このコマンドは、blogs.controller.spec.tsに2つのファイルを作成します および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(マングース)。

    実行してマングースをインストールし、

    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 }]),
      ],
    

    挿入スキーマ

    blogsを挿入する必要があります blogs.service.tsにモデル化する @InjectModel()を使用する デコレータ。これを達成するには、次のことを行う必要があります

    • import { Model } 'mongoose'から 、
    • import { InjectModel } '@nestjs/mongoose’から 、
    • インポート{Blog, BlogDocument} './schemas/blogs.schema’から 、
    • constructorを作成します BlogsService内 クラス、
    • privateを宣言します 変数をblogModelと呼びます タイプをModel<BlogDocument>に割り当てます それに。すべてのマングースメソッドがこの変数で呼び出されます。

    BlogDocumentを思い出してください Blogの共用体タイプです クラスとマングースの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というクラス 、1つのパラメータを取ります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として定義するデコレータ request。createBlog 1つのパラメータを取りますblog 、タイプはBlogInterface 。パラメータを@Bodyでマークします body全体を抽出するデコレータ reqのオブジェクト オブジェクトを作成し、装飾されたパラメータにbodyの値を入力します 。

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

    読む

    2つのasyncを追加します メソッド。1つは単一のブログ投稿を返し、もう1つはすべてのブログ投稿を返します。

    サービスロジック

    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として定義するデコレータ リクエスト。

    2番目の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 関数の2番目のパラメーターは、@Body()でマークされています body全体を抽出するデコレータ reqのオブジェクト オブジェクトを作成し、装飾されたパラメータにbodyの値を入力します 。

    削除

    deleteのロジックを実装しましょう リクエスト。

    サービスロジック

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

    Promise 総称型はvoidです Delete リクエストは空のpromiseを返します。

    コントローラーロジック

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

    APIのテスト

    このAPIをテストするには、APIテストツールを使用する必要があります。この記事では、Postmanと呼ばれる人気のあるAPIテストツールを使用します。人気のあるトピックに関するランダムなデータを使用してテストします。

    作成

    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へのリクエスト 。これは

    を返すはずです

    200 以前に追加したすべてのデータの配列による応答。 _idをコピーします 配列オブジェクトの1つのプロパティ。

    別のGETを作成します http://localhost/3000/blogs/idへのリクエスト 以前にコピーされたIDを使用します。これにより、200が返されます。 IDがリクエストの作成に使用されたオブジェクトのデータによる応答。

    更新

    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. マングースの__vフィールドとは何ですか

    2. コンソールでMongoDBログメッセージを無効にするにはどうすればよいですか?

    3. Cloudera Data Platformオペレーショナルデータベース(COD)入門

    4. MongoDBコレクション内に特定の埋め込みドキュメントを取得するにはどうすればよいですか?