发布于 2026-01-06 0 阅读
0

NestJS 的 NoSQL Azure 表存储简介🚀 什么是 Azure 表存储? 设置 NestJS Azure 存储安装 准备业务逻辑 整合所有内容 总结

隆重推出适用于 NestJS 的 NoSQL Azure 表存储🚀

什么是 Azure 表存储?

准备工作

NestJS Azure 存储安装

准备我们的业务逻辑

把所有东西放在一起

综上所述

最初发表于Trilon 博客,日期为 2019 年 9 月 17 日。

在本文中,我们将介绍如何使用新的库在短短几分钟内将 Azure 表存储添加到我们的 NestJS 应用程序中@nestjs/azure-database

如果您还不熟悉NestJS,它是一个 TypeScript Node.js 框架,可以帮助您构建企业级高效且可扩展的 Node.js 应用程序。

什么是 Azure 表存储?

Azure 表存储是一个 NoSQL 键值存储,使用海量半结构化数据集。

表存储允许您创建需要灵活数据模式的大规模可扩展应用程序。您还可以执行基于 OData 的查询并使用 JSON 序列化数据。

使用 Azure 表存储来存储 PB 级半结构化数据,并降低成本。

与许多数据存储(无论是本地存储还是云端存储)不同:

  • 表存储允许您扩展规模,而无需手动对数据集进行分片。
  • 供货情况也完全不成问题!
  • 利用异地冗余存储,存储的数据在一个区域内复制三次,并在数百英里外的另一个区域再复制三次。

让我们深入了解一下如何在 NestJS 应用程序中使用表格存储!

准备工作

注意:在本演示中,我们将展示一个由 CLI 生成的新的 NestJS 应用程序,但如果您更喜欢使用现有的 NestJS 应用程序,请随意跳过此步骤!

生成一个新的 NestJS 应用程序

为了演示目的,让我们确保已安装最新版本的 NestJS CLI,并创建一个新应用程序。

$ npm i -g @nestjs/cli
$ nest new PROJECT_NAME
Enter fullscreen mode Exit fullscreen mode

现在让我们cd进入新创建的目录并打开我们的IDE。此时,我们已经生成了一个简单的NestJS应用程序。

设置 Azure 存储帐户

要使用表存储,我们需要创建一个 Azure 存储帐户。您可以按照此分步指南进行操作。

创建存储帐户后,我们需要复制 SDK 将要使用的连接字符串。在Azure 门户中,转到“仪表板”>“存储”>“您的存储帐户”:

替代文字

记下“设置”选项卡下“访问密钥”中获取的“存储帐户名称”和“连接字符串”。

提示:连接字符串应以DefaultEndpointsProtocol=

NestJS Azure 存储安装

接下来,我们需要@nestjs/azure-database从 NPM 安装 SDK:

$ npm i --save @nestjs/azure-database dotenv
Enter fullscreen mode Exit fullscreen mode

我们还安装了dotenv用于处理环境变量的软件包。

然后,我们将创建一个名为 .env 的文件,内容如下:

AZURE_STORAGE_CONNECTION_STRING="<the connection string we copied from previous step>"
Enter fullscreen mode Exit fullscreen mode

还有一点非常重要:我们会确保将我们的.env文件添加到.gitignore!该.env文件绝对不能在 Git 上进行版本控制。

文件创建完毕后.env,我们将向其中添加以下调用src/main.ts

if (process.env.NODE_ENV !== 'production') require('dotenv').config();
Enter fullscreen mode Exit fullscreen mode

提示:此行必须添加到文件中的任何其他导入语句之前src/main.ts

我们的环境已经准备就绪。接下来让我们实现应用程序的逻辑。

准备我们的业务逻辑

NestJS 中的 Azure 表存储支持遵循对象关系映射 (ORM) 设计模式,它本质上是一种从我们的代码访问数据库的“结构化”方式,允许您使用 API 而不是编写实际的 SQL 代码。

为了实现这种设计模式,我们需要为每个功能创建以下组件:

  • DTO(或数据传输对象)
    • 这是代表我们数据的对象。DTO 主要用于在应用程序服务之间传输数据,例如在 HTTP 服务和浏览器之间传输数据。
  • Entity
    • 这基本上是一个映射到表结构的类。
  • Repository
    • 这是负责与数据库通信的组件。

首先,我们创建一个 NestJS 功能模块,用于存放我们的功能业务逻辑。我们将使用 NestJS CLI 来创建Cat功能:

$ nest generate module cat
Enter fullscreen mode Exit fullscreen mode

注意:我们将在流程结束时再回到我们生成的模块。

DTO

我们需要为我们的Cat功能创建的第一个组件是 DTO。在名为 `<filename>` 的文件中cat.dto.ts,我们创建以下类:

export class CatDTO {
  name: string;
  age: number;
}
Enter fullscreen mode Exit fullscreen mode

实体

接下来,我们需要一个模型Entity。为此,我们创建一个名为 `model.xml` 的文件cat.entity.ts,并使用 `model.xml` 提供的装饰器来描述该模型@nestjs/azure-database

实体 代表 必需的
@EntityPartitionKey(value: string) PartitionKey实体 是的
@EntityRowKey(value: string) RowKey实体 是的
@EntityInt32(value?: string) 有符号 32 位整数值
@EntityInt64(value?: string) 有符号 64 位整数值
@EntityBinary(value?: string) 二进制(blob)数据
@EntityBoolean(value?: string) truefalse
@EntityString(value?: string) 字符数据
@EntityDouble(value?: string) 精度为 15 位的浮点数
@EntityDateTime(value?: string) 一天中的时间

注意:稳定版本中 API 可能会略有变化。

例如,以下实体的形状:

import {
  EntityPartitionKey,
  EntityRowKey,
  EntityString,
  EntityIn32
} from '@nestjs/azure-database';

@EntityPartitionKey('CatID')
@EntityRowKey('CatName')
export class Cat {
  @EntityString() name: string;
  @EntityIn32() age: number;
}
Enter fullscreen mode Exit fullscreen mode

Cat实体将自动转换为 Azure 表存储所期望的以下架构:

{
  "PartitionKey": { "_": "CatID", "$": "Edm.String" },
  "RowKey": { "_": "CatName", "$": "Edm.String" },
  "name": { "_": undefined, "$": "Edm.String" },
  "age": { "_": undefined, "$": "Edm.Int32" }
}
Enter fullscreen mode Exit fullscreen mode

存储库

在创建了 DTO 和实体之后,我们现在需要创建一个Cat服务来抽象所有与该实体相关的 CRUD 操作Cat。此服务将使用 Azure 表存储Repository

让我们使用 NestJS CLI 创建一个服务:

$ nest generate service cat
Enter fullscreen mode Exit fullscreen mode

在创建的容器中cat.service.ts,我们导入该容器Repository,并为其提供Cat上一步中创建的实体定义:

import { Injectable } from '@nestjs/common';
import { Repository, InjectRepository } from '@nestjs/azure-database';
import { Cat } from './cat.entity';

@Injectable()
export class CatService {
  constructor(
    @InjectRepository(Cat)
    private readonly catRepository: Repository<Cat>,
  ) {}

  // ... other code ...
Enter fullscreen mode Exit fullscreen mode

Azure 表存储Repository接口提供了一系列公共 API 和类型,用于管理各种 CRUD(Create添加、Read删除Update和更新)操作。接下来,我们将了解如何使用SDKDelete实现每种不同的操作。@nestjs/azure-database

我们将调用的方法如下:

  • create(entity: T): Promise<T>创建一个新实体。
  • findAll(tableQuery?: azure.TableQuery, currentToken?: azure.TableService.TableContinuationToken): Promise<AzureTableStorageResultList<T>>查找与给定查询匹配的所有实体(如果没有提供查询,则返回所有实体)。
  • find(rowKey: string, entity: Partial<T>): Promise<T>使用 RowKey 查找实体。
  • update(rowKey: string, entity: Partial<T>): Promise<T>更新实体。此操作执行部分更新。
  • delete(rowKey: string, entity: T): Promise<AzureTableStorageResponse>使用 RowKey 删除实体。

以下是此类实现的一个示例:

import { Injectable } from '@nestjs/common';
import { Repository, InjectRepository } from '@nestjs/azure-database';
import { Cat } from './cat.entity';

@Injectable()
export class CatService {
  constructor(
    @InjectRepository(Cat)
    private readonly catRepository: Repository<Cat>,
  ) {}

  // find one cat entitu by its rowKey
  async find(rowKey: string, cat: Cat): Promise<Cat> {
    return this.catRepository.find(rowKey, cat);
  }

  // find all cat entities
  async findAll(): Promise<AzureTableStorageResultList<Cat>> {
    return this.catRepository.findAll();
  }

  // create a new cat entity
  async create(cat: Cat): Promise<Cat> {
    return this.catRepository.create(cat);
  }

  // update the a cat entity by its rowKey
  async update(rowKey: string, cat: Partial<Cat>): Promise<Cat> {
    return this.catRepository.update(rowKey, cat);
  }

  // delete a cat entity by its rowKey
  async delete(rowKey: string, cat: Cat): Promise<AzureTableStorageResponse> {
    return this.catRepository.delete(rowKey, cat);
  }
}
Enter fullscreen mode Exit fullscreen mode

控制器

最后一步是实现用于处理 HTTP 请求的 NestJS 控制器。让我们使用 NestJS CLI 创建这样一个控制器:

$ nest generate controller cat
Enter fullscreen mode Exit fullscreen mode

控制器的实现很简单,可能取决于您的应用程序业务需求。以下是一个实现示例:

import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Post,
  Put,
  UnprocessableEntityException,
  NotFoundException,
  Patch
} from '@nestjs/common';
import { CatDto } from './cat.dto';
import { Cat } from './cat.entity';
import { CatService } from './cat.service';

@Controller('cats')
export class CatController {
  constructor(private readonly catService: CatService) {}

  @Get()
  async getAllCats() {
    return await this.catService.findAll();
  }

  @Get(':rowKey')
  async getCat(@Param('rowKey') rowKey) {
    try {
      return await this.catService.find(rowKey, new Cat());
    } catch (error) {
      // Entity not found
      throw new NotFoundException(error);
    }
  }

  @Post()
  async createCat(
    @Body()
    catData: CatDto,
  ) {
    try {
      const cat = new Cat();
      // Disclaimer: Assign only the properties you are expecting!
      Object.assign(cat, catData);

      return await this.catService.create(cat);
    } catch (error) {
      throw new UnprocessableEntityException(error);
    }
  }

  @Put(':rowKey')
  async saveCat(@Param('rowKey') rowKey, @Body() catData: CatDto) {
    try {
      const cat = new Cat();
      // Disclaimer: Assign only the properties you are expecting!
      Object.assign(cat, catData);

      return await this.catService.update(rowKey, cat);
    } catch (error) {
      throw new UnprocessableEntityException(error);
    }
  }

  @Patch(':rowKey')
  async updateCatDetails(@Param('rowKey') rowKey, @Body() catData: Partial<CatDto>) {
    try {
      const cat = new Cat();
      // Disclaimer: Assign only the properties you are expecting!
      Object.assign(cat, catData);

      return await this.catService.update(rowKey, cat);
    } catch (error) {
      throw new UnprocessableEntityException(error);
    }
  }

  @Delete(':rowKey')
  async deleteDelete(@Param('rowKey') rowKey) {
    try {
      const response = await this.catService.delete(rowKey, new Cat());

      if (response.statusCode === 204) {
        return null;
      } else {
        throw new UnprocessableEntityException(response);
      }
    } catch (error) {
      throw new UnprocessableEntityException(error);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

把所有东西放在一起

我们已经完成了该功能的实现Cat。在最后一步中,我们需要将之前创建的AzureTableStorageModuleNest 功能模块导入到其中:cat.module.ts

import { Module } from '@nestjs/common';
import { AzureTableStorageModule } from '@nestjs/azure-database';
import { CatController } from './cat.controller';
import { CatService } from './cat.service';
import { Cat } from './cat.entity';

@Module({
  imports: [AzureTableStorageModule.forFeature(Cat)],
  providers: [CatService],
  controllers: [CatController],
})
export class CatModule {}
Enter fullscreen mode Exit fullscreen mode

AzureTableStorageModule模块接受几个可选参数:

AzureTableStorageModule.forFeature(Cat, {
  table: 'AnotherTableName',
  createTableIfNotExists: true,
})
Enter fullscreen mode Exit fullscreen mode
  • table: string表名。如果未提供,则将使用 Cat 实体的名称作为表名。
  • createTableIfNotExists: boolean是否在表不存在时自动创建该表:
    • 如果true表格将在应用程序启动期间创建。
    • 如果false表未创建,则必须先自行创建表才能进行查询!

综上所述

我们刚刚Cat为应用程序实现了一个新功能,该功能使用@nestjs/azure-database官方软件包来添加对 Azure 表存储的支持。借助 NestJS 的模块化系统,我们可以像安装 Nest 原生功能一样轻松地将其安装并集成到我们的应用程序中!

如果您有兴趣了解更多关于使用 Azure 的 Serverless NestJS 应用程序的信息,请点击此处阅读更多内容

GitHub 标志 nestjs / azure-database

适用于 Nest 框架 (node.js) 的 Azure CosmosDB 数据库模块 ☁️

巢标志

一个用于构建高效、可扩展的服务器端应用程序的渐进式Node.js框架。

NPM 版本 软件包许可证 NPM 下载 覆盖范围 Discord Open Collective 的支持者 Open Collective 上的赞助商

描述

适用于Nest框架 (node.js)的Azure 数据库(表存储Cosmos DB - NoSQL)模块

免责声明

您正在阅读的是版本 3 的文档。如果您正在查找版本 2 的文档,请点击此处。另请注意,版本 2 已停止维护,不会再收到任何更新!

安装前

适用于 Cosmos DB(仅限 NoSQL)

  1. 创建 Cosmos DB 帐户和资源(了解更多
  2. 记下“URI”、数据库名称和“主键”(或“辅助键”)——稍后会用到它们。

用于桌面收纳

  1. 创建存储帐户和资源(了解更多
  2. 记下“连接字符串”——稍后会用到。

安装

$ npm i --save @nestjs/azure-database
Enter fullscreen mode Exit fullscreen mode

用法

针对 Azure Cosmos DB 的支持

  1. .env使用以下内容创建或更新现有文件:
AZURE_COSMOS_DB_NAME=
AZURE_COSMOS_DB_ENDPOINT=
文章来源:https://dev.to/azure/introducing-nosql-azure-table-storage-for-nestjs-291m