NestJs 中使用 mongoose

在 NestJS 中鏈接 MongoDB 有兩種方法。一種方法就是使用TypeORM來進行連接,另外一種方法就是使用Mongoose

此筆記主要是記錄使用Mongoose的。所以我們先安裝所需的依賴:

npm i @nestjs/mongoose mongoose

安裝完成后,需要在AppModule中引入MongooseModule。具體實例如下:

import databaseConfig from "./config/database.config";
import { MongooseModule } from "@nestjs/mongoose";@Module({imports: [MongooseModule.forRoot("mongodb://localhost:27017/managementsytem"),CommodityModule,],
})
export class AppModule {}

MongooseModule.forRoot中的配置對象與mongoose.connect()的配置對象一致。

模型注入

在 Mongoose 中最為核心的是模式,因為每個模式都會轉換成一個具體的MongoDB集合,并且模式定義了集合中文檔的結構。

在 Mongoose 中模型主要是負責從底層創建數據和讀取文檔。

在 NestJs 中模式可以使用裝飾器來創建,也可以使用 Mongoose 本身手動創建。使用裝飾器創建的模式在代碼量和代碼可讀性上都比 Mongoose 本身手動創建的要好。所以建議使用裝飾器來創建模式。具體的實例如下:

import { HydratedDocument } from "mongoose";
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";export type CommodityDocument = HydratedDocument<Commodity>;@Schema()
export class Commodity {@Prop()name: string; // 商品名稱@Prop()price: number; // 商品價格@Prop()stock: number; // 商品庫存@Prop([String])tag: string; // 商品標簽
}export const CommoditySchema = SchemaFactory.createForClass(Commodity);

注意:
您還可以使用 DefinitionsFactory 類生成原始模式定義。這允許您手動修改根據您提供的元數據生成的架構定義。當模型的字段可能會進行擴展和刪除的時候,我們就可以使用DefinitionsFactory來維護模式的數據。

@Schema()裝飾器的作用主要是定義模式。在上述的例子中會把Commodity類映射到同名的MongoDB集合中,但是需要注意的是在 MongoDB 集合中的名稱會添加一個’s’,即Commoditys。此裝飾器可以接受一個可選參數,此參數主要是用于設置 MongoDB 的模型相關參數,具體的內容可以進入這里查看。

@Prop() 裝飾器定義文檔中的屬性。例如,在上面的模式定義中,我們定義了三個屬性:名稱、價格和標簽。借助 TypeScript 元數據(和反射)功能,可以自動推斷這些屬性的架構類型。但是,在無法隱式反映類型的更復雜場景(例如數組或嵌套對象結構)中,必須顯式指示類型,如下所示:

@Prop([String])
tags: string[];

或者,@Prop() 裝飾器接受選項對象參數(閱讀有關可用選項的更多信息)。這樣,您可以指示屬性是否是必需的、指定默認值或將其標記為不可變。例如:

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

如果一個模型中帶有另外一個屬性的話,可以使用@Prop()裝飾器。例如,Commodity 里面包含一個 supply 模型,這樣我們需要在 Commodity 里面添加具體的類和引用。具體例子如下:

import * as mongoose from 'mongoose';
import { Supply } from '../owners/schemas/supply.schema';@Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'Supply' })
supply: Supply;

如果有多個提供商,您的屬性配置應如下所示:

@Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Supply' }] })
supply: Supply[];

最后,原始模式定義也可以傳遞給裝飾器。例如,當屬性表示未定義為類的嵌套對象時,這很有用。為此,請使用 @nestjs/mongoose 包中的 raw() 函數,如下所示:

@Prop(raw({firstName: { type: String },lastName: { type: String }
}))
details: Record<string, any>;

或者,如果您不想使用裝飾器,則可以手動定義架構。例如:

export const CommoditySchema = new mongoose.Schema({name: String,price: Number,stock: Number,tags: [String],
});

當我們定義好模式后,就可以在對應的Module中進行定義,具體實例如下:

@Module({imports: [ConfigModule,MongooseModule.forFeature([{ name: Commodity.name, schema: CommoditySchema },]),],controllers: [CommodityController],providers: [CommodityService],
})
export class CommodityModule {}

MongooseModule 提供了 forFeature() 方法來配置模塊,包括定義應在當前范圍內注冊哪些模型。如果您還想在另一個模塊中使用模型的話,你只要在 CommodityModule 中添加 MongooseModule 作為導出部分,并在另一個模塊中導入 CommodityModule 就可以。

注冊模式后,您可以使用 @InjectModel() 裝飾器將 Commodity 模型注入到 CommodityService 中:

import { Injectable } from "@nestjs/common";
import { InjectModel } from "@nestjs/mongoose";
import { Model } from "mongoose";
import { Commodity } from "src/schemas/commodity.schemas";@Injectable()
export class CommodityService {constructor(@InjectModel(Commodity.name) private commodityModel: Model<Commodity>) {}create(commodity: Commodity) {const createdCommdity = new this.commodityModel(commodity);return createdCommdity.save();}
}

獲取 Mongoose Connection 對象

有時您可能需要訪問本機 Mongoose Connection 對象。例如,您可能希望對連接對象進行本機 API 調用。您可以使用 @InjectConnection() 裝飾器注入 Mongoose Connection,如下所示:

import { Injectable } from "@nestjs/common";
import { InjectConnection } from "@nestjs/mongoose";
import { Connection } from "mongoose";@Injectable()
export class CatsService {constructor(@InjectConnection() private connection: Connection) {}
}

多個數據庫使用

有些項目需要多個數據庫連接。這也可以通過該模塊來實現。要使用多個連接,請首先創建連接。在這種情況下,連接命名就成為強制性的。具體實例如下:

import { Module } from "@nestjs/common";
import { CommodityModule } from "./module/commodity.module";
import { AccountModule } from "./module/account.module";
import { ConfigModule } from "@nestjs/config";
import configuration from "./config/configuration";
import databaseConfig from "./config/database.config";
import { MongooseModule } from "@nestjs/mongoose";@Module({imports: [ConfigModule.forRoot({load: [configuration, databaseConfig],cache: true,}),MongooseModule.forRoot("mongodb://localhost:27017/managementsytem", {connectionName: "commodity",}),MongooseModule.forRoot("mongodb://localhost:27018/user", {connectionName: "user",}),CommodityModule,AccountModule,],
})
export class AppModule {}

**注意:**您不應有多個沒有名稱或名稱相同的連接,否則它們將被覆蓋。

假如你設置了多個數據鏈接后,你必須在對應的模塊中使用MongooseModule.forFeature()函數來聲明鏈接哪個數據庫。具體的例子如下:

@Module({imports: [ConfigModule,MongooseModule.forFeature([{ name: Commodity.name, schema: CommoditySchema }],"commodity"),],controllers: [CommodityController],providers: [CommodityService],exports: [CommodityService],
})
export class CommodityModule {}

如果您在 AppModule 中聲明了多個數據庫,并在對應的模塊中聲明了鏈接的數據庫名稱,那么我們的提供者就需要在裝飾器中添加第二個參數。具體實例如下:

@Injectable()
export class CatsService {constructor(@InjectModel(Commodity.name, "commodities")private commodityModel: Model<Commodity>) {}async create(commodity: Commodity) {const createdCommdity = new this.commodityModel(commodity);const _res = await createdCommdity.save();return _res;}
}

您還可以為給定連接注入連接:

import { Injectable } from "@nestjs/common";
import { InjectConnection } from "@nestjs/mongoose";
import { Connection } from "mongoose";@Injectable()
export class CommodityService {constructor(@InjectConnection("commodity") private connection: Connection) {}
}

要將給定連接注入到自定義提供程序(例如工廠提供程序),請使用 getConnectionToken() 函數,將連接名稱作為參數傳遞。

{provide: CommodityService,useFactory: (commodityConnection: Connection) => {return new CommodityService(commodityConnection);},inject: [getConnectionToken('commodity')],
}

Mongo 鉤子(中間件)

Mongo 鉤子的使用場景一般都是在編寫自己的插件時才會使用。

Mongo 的中間件是在模式級別指定的,對于編寫插件很有用。編譯模型后調用 pre() 或 post() 在 Mongoose 中不起作用。要在模型注冊之前注冊鉤子,請使用 MongooseModule 的 forFeatureAsync() 方法以及工廠提供程序(即 useFactory)。通過這種技術,您可以訪問模式對象,然后使用 pre() 或 post() 方法在該模式上注冊掛鉤。具體實例如下:

@Module({imports: [MongooseModule.forFeatureAsync([{name: Commodity.name,useFactory: () => {const schema = CommoditySchema;schema.pre("save", function () {console.log("Hello from pre save");});return schema;},},]),],
})
export class AppModule {}

與其他工廠提供者一樣,我們的工廠函數可以是異步的,并且可以通過注入注入依賴項。

@Module({imports: [MongooseModule.forFeatureAsync([{name: Commodity.name,imports: [ConfigModule],useFactory: (configService: ConfigService) => {const schema = CommoditySchema;schema.pre('save', function() {console.log(`${configService.get('APP_NAME')}: Hello from pre save`,),});return schema;},inject: [ConfigService],},]),],
})
export class AppModule {}

中間件中使用插件

要為給定架構注冊插件,請使用 forFeatureAsync() 方法。

@Module({imports: [MongooseModule.forFeatureAsync([{name: Commodity.name,useFactory: () => {const schema = CommoditySchema;schema.plugin(require("mongoose-autopopulate"));return schema;},},]),],
})
export class AppModule {}

要一次為所有模式注冊插件,請調用 Connection 對象的 .plugin() 方法。您應該在創建模型之前訪問連接;為此,請使用連接工廠:

import { Module } from "@nestjs/common";
import { MongooseModule } from "@nestjs/mongoose";@Module({imports: [MongooseModule.forRoot("mongodb://localhost/test", {connectionFactory: (connection) => {connection.plugin(require("mongoose-autopopulate"));return connection;},}),],
})
export class AppModule {}

鑒別器

鑒別器是一種模式繼承機制。它們使您能夠在同一底層 MongoDB 集合之上擁有具有重疊架構的多個模型。這個功能相當于模型形成繼承關系。

假設您想在單個集合中跟蹤不同類型的事件。每個事件都會有一個時間戳。

@Schema({ discriminatorKey: "kind" })
export class Event {@Prop({type: String,required: true,enum: [ClickedLinkEvent.name, SignUpEvent.name],})kind: string;@Prop({ type: Date, required: true })time: Date;
}export const EventSchema = SchemaFactory.createForClass(Event);

SignedUpEvent 和 ClickedLinkEvent 實例將與通用事件存儲在同一集合中。

現在,讓我們定義 ClickedLinkEvent 類,如下所示:

@Schema()
export class ClickedLinkEvent {kind: string;time: Date;@Prop({ type: String, required: true })url: string;
}export const ClickedLinkEventSchema =SchemaFactory.createForClass(ClickedLinkEvent);

和 SignUpEvent 類:

@Schema()
export class SignUpEvent {kind: string;time: Date;@Prop({ type: String, required: true })user: string;
}export const SignUpEventSchema = SchemaFactory.createForClass(SignUpEvent);

完成此操作后,使用鑒別器選項為給定模式注冊鑒別器。它適用于 MongooseModule.forFeature 和 MongooseModule.forFeatureAsync:

import { Module } from "@nestjs/common";
import { MongooseModule } from "@nestjs/mongoose";@Module({imports: [MongooseModule.forFeature([{name: Event.name,schema: EventSchema,discriminators: [{ name: ClickedLinkEvent.name, schema: ClickedLinkEventSchema },{ name: SignUpEvent.name, schema: SignUpEventSchema },],},]),],
})
export class EventsModule {}

完成上述的代碼后,其實模型之間的關系如下:

在這里插入圖片描述

異步配置

當您需要異步而不是靜態地傳遞模塊選項時,請使用 forRootAsync() 方法。與大多數動態模塊一樣,Nest 提供了多種處理異步配置的技術。

一種技術是使用工廠函數:

MongooseModule.forRootAsync({useFactory: () => ({uri: "mongodb://localhost/nest",}),
});

與其他工廠提供者一樣,我們的工廠函數可以是異步的,并且可以通過注入注入依賴項。

MongooseModule.forRootAsync({imports: [ConfigModule],useFactory: async (configService: ConfigService) => ({uri: configService.get<string>("MONGODB_URI"),}),inject: [ConfigService],
});

或者,您可以使用類而不是工廠來配置 MongooseModule,如下所示:

MongooseModule.forRootAsync({useClass: MongooseConfigService,
});

上面的構造在 MongooseModule 中實例化 MongooseConfigService,使用它來創建所需的選項對象。請注意,在此示例中,MongooseConfigService 必須實現 MongooseOptionsFactory 接口,如下所示。MongooseModule 將在所提供的類的實例化對象上調用 createMongooseOptions() 方法。

@Injectable()
export class MongooseConfigService implements MongooseOptionsFactory {createMongooseOptions(): MongooseModuleOptions {return {uri: "mongodb://localhost/nest",};}
}

如果您想重用現有的選項提供程序而不是在 MongooseModule 內創建私有副本,請使用 useExisting 語法。

MongooseModule.forRootAsync({imports: [ConfigModule],useExisting: ConfigService,
});

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/39297.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/39297.shtml
英文地址,請注明出處:http://en.pswp.cn/news/39297.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringBoot后端服務開啟Https協議提供訪問(使用阿里云資源)

目錄 概述 申請/下載證書 部署證書 本地測試訪問 服務器部署訪問 最后/擴展 總結 概述 本篇博客說明如何將SpringBoot項目開啟Https協議提供訪問。 博文以步驟【申請/下載證書】&#xff0c;【部署證書】&#xff0c;【本地測試訪問】&#xff0c;【服務器部署訪問】 &a…

SIP/VoIP之常見的視頻問題

除了語音通話外&#xff0c;視頻通話也是SIP協議通話中重要的功能&#xff0c;在實際應用中&#xff0c;經常會遇到一些視頻問題&#xff0c;如下&#xff08;以h264為例&#xff09; 一、 己方未顯示對方視頻圖像 排查方法&#xff1a; 查看網絡抓包中有沒有發給已方的視頻…

LORA開發板采集溫濕度數據,連接PC上位機顯示和液晶屏顯示

一、準備材料 準備以下板子和器件 Lora開發板x2 USB數據線x2 OLED 屏幕x2 StLink下載器x1 母對母杜邦線x3 DHT11 x2 二、設備連接 如圖所示先將OLED 屏幕插入到開發板中 接著按照圖中所示的&#xff0c;將串口一以及lora的撥碼開關撥到指定方向 接著將USB數據線一端插入到…

SQL Server用sql語句添加列,添加列注釋

SQL Server用sql語句添加列&#xff0c;添加列注釋 微軟文檔&#xff1a; https://learn.microsoft.com/zh-cn/sql/relational-databases/tables/add-columns-to-a-table-database-engine?viewsql-server-ver15 alter table article add RedirectURL varchar(600) nu…

(七)Unity VR項目升級至Vision Pro需要做的工作

Vision Pro 概述 定位為混合現實眼鏡&#xff0c;對AR支持更友好 無手柄&#xff0c;支持手&#xff08;手勢&#xff09;、眼&#xff08;注視&#xff09;、語音交互 支持空間音頻&#xff0c;相比立體聲、環繞聲更有沉浸感和空間感 支持VR/AR應用&#xff0c;支持多種應用模…

八字精批API接口

接口平臺&#xff1a;https://api.yuanfenju.com/ 開發文檔&#xff1a;https://doc.yuanfenju.com/ 支持格式&#xff1a;JSON 請求方式&#xff1a;HTTP POST <?php//密鑰 $api_secret "wD******XhOUW******pvr"; //請求網關 $gateway_host_url "ht…

FPGA應用學習筆記-----復位電路(二)和小結

不可復位觸發器若和可復位觸發器混合寫的話&#xff0c;不可復位觸發器是由可復位觸發器饋電的。 不應該出現的復位&#xff0c;因為延時導致了冒險&#xff0c;異步復位存在靜態冒險 附加素隱含項&#xff0c;利用數電方法&#xff0c;消除靜態冒險 這樣多時鐘區域還是算異步的…

【Docker】如何在設計 dockerfile 過程中,設置容器啟動后的定時任務

如何在設計 dockerfile 過程中&#xff0c;設置容器啟動后的定時任務 jwensh 2023.08.14 文章目錄 如何在設計 dockerfile 過程中&#xff0c;設置容器啟動后的定時任務1. 基于 alpine 設計 dockerfile 過程中&#xff0c;設置容器啟動后的定時任務2. 基于 CentOS 設計 Dockerf…

深度學習實戰基礎案例——卷積神經網絡(CNN)基于SqueezeNet的眼疾識別|第1例

文章目錄 前言一、數據準備1.1 數據集介紹1.2 數據集文件結構 二、項目實戰2.1 數據標簽劃分2.2 數據預處理2.3 構建模型2.4 開始訓練2.5 結果可視化 三、數據集個體預測 前言 SqueezeNet是一種輕量且高效的CNN模型&#xff0c;它參數比AlexNet少50倍&#xff0c;但模型性能&a…

Linkedin為什么要退出中國市場?

在迅速發展的時代,職場也在不斷變換,只有不斷地提升專業技能和進行培訓,才能在職場中獲得成功。Linkedin作為一家專注于職業發展的平臺,專業的學習體驗以及熱門技能贏得了人們青睞。然而遺憾的是這個曾經讓人備受青睞的平臺,如今卻在中國市場中黯然落幕,究竟是何種原因讓曾經風…

大數據Flink(六十一):Flink流處理程序流程和項目準備

文章目錄 Flink流處理程序流程和項目準備 一、Flink流處理程序的一般流程

Springboot 設置統一的請求返回格式

現在開發過程中主要采用前后端分離的方式進行開發測試&#xff0c;也就是前端封裝請求&#xff0c;后端提供標準的API接口服務。一般現在json 格式受到開發者們的青睞&#xff0c;學習過程中我們可以設置接口的返回類型&#xff0c;那么怎么做到設置統一的返回格式呢&#xff1…

數據在內存中的存儲(二進制形式存儲)

計算機要處理的信息是多種多樣的&#xff0c;如數字、文字、符號、圖形、音頻、視頻等&#xff0c;這些信息在人們的眼里是不同的。但對于計算機來說&#xff0c;它們在內存中都是一樣的&#xff0c;都是以二進制的形式來表示。 要想學習編程&#xff0c;就必須了解二進制&…

Spark SQL優化:NOT IN子查詢優化解決

背景 有如下的數據查詢場景。 SELECT a,b,c,d,e,f FROM xxx.BBBB WHERE dt ${zdt.addDay(0).format(yyyy-MM-dd)} AND predict_type not IN ( SELECT distinct a FROM xxx.AAAAAWHERE dt ${zdt.addDay(0).format(yyyy-MM-dd)} ) 分析 通過查看SQL語句的執行計劃基本…

Dubbo基礎學習(筆記一)

目錄 第一章、概念介紹1.1&#xff09;什么是RPC框架1.2&#xff09;什么是分布式系統1.3&#xff09;Dubbo概述1.3&#xff09;Dubbo基本架構 第二章、服務提供者2.1&#xff09;目錄結構和依賴2.2&#xff09;model層2.3&#xff09;service層2.4&#xff09;resources配置文…

ARTS 挑戰打卡的第8天 ---volatile 關鍵字在MCU中的作用,四個實例講解(Tips)

前言 &#xff08;1&#xff09;volatile 關鍵字作為嵌入式面試的常考點&#xff0c;很多人都不是很了解&#xff0c;或者說一知半解。 &#xff08;2&#xff09;可能有些人會說了&#xff0c;volatile 關鍵字不就是防止編譯器優化的嗎&#xff1f;有啥好詳細講解的&#xff1…

HashMap底層相關內容

HashMap的底層結構&#xff1a; 1.7之前 數組加鏈表&#xff0c;當兩個值進行插入的時候 采用頭插法進行插入&#xff0c;可能會造成死循環 1.8之后 數組加鏈表/紅黑樹&#xff0c;當兩個值進行插入的時候&#xff0c;采用尾插法進行插入&#xff0c;不會造成死循環 HashMap底…

xml轉map工具類

背景&#xff1a;最近遇到接口返回是xml&#xff0c;所以需要整一個轉換的工具類&#xff0c;方便后續其他xml處理。 依賴引入&#xff1a; <dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.1</versi…

澎峰科技|邀您關注2023 RISC-V中國峰會!

峰會概覽 2023 RISC-V中國峰會&#xff08;RISC-V Summit China 2023&#xff09;將于8月23日至25日在北京香格里拉飯店舉行。本屆峰會將以“RISC-V生態共建”為主題&#xff0c;結合當下全球新形勢&#xff0c;把握全球新時機&#xff0c;呈現RISC-V全球新觀點、新趨勢。 本…

linux下nginx配置https和反向代理本地端口

1 修改配置文件/etc/nginx/sites-enabled/default 在配置文件中增加一個server用來做https端口監聽&#xff0c; ssl_certificate和ssl_certificate_key修改為自己申請的https認證文件 server{listen 443 ssl;server_name www.dogrich.net;#root /var/www/html;# 上面配置的…