A progressive Node.js framework for building efficient and scalable server-side applications.
Azure Database (Table Storage, Cosmos DB - NoSQL) module for Nest framework (node.js)
You are reading the documentation for version 3. If you are looking for version 2 documentation, click here. Please also note that version 2 is no longer maintained and will not receive any updates!
For Cosmos DB (NoSQL ONLY)
- Create a Cosmos DB account and resource (read more)
- Note down the "URI", Database name and the "Primary Key" (or "Secondary Key") - You will need them later
For Table Storage
- Create a Storage account and resource (read more)
- Note down the "Connection string" - You will need it later
$ npm i --save @nestjs/azure-database- Create or update your existing
.envfile with the following content:
AZURE_COSMOS_DB_NAME=
AZURE_COSMOS_DB_ENDPOINT=
AZURE_COSMOS_DB_KEY=
-
IMPORTANT: Make sure to add your
.envfile to your .gitignore! The.envfile MUST NOT be versioned on Git. -
Make sure to include the following call to your
main.tsfile:
if (process.env.NODE_ENV !== 'production') require('dotenv').config();This line must be added before any other imports!
Note: Check out the CosmosDB example project included in the sample folder
- Create a new feature module, eg. with the nest CLI:
$ nest generate module event- Create a Data Transfer Object (DTO) inside a file named
event.dto.ts:
export class EventDTO {
id?: string;
name: string;
type: string;
createdAt: Date;
}- Create a file called
event.entity.tsand describe the entity model using the provided decorators:
-
@CosmosPartitionKey(value: string | HierarchicalPartitionKey): Represents thePartitionKeyorHierarchicalPartitionKeyof the entity (required). -
@CosmosDateTime(value?: string): For DateTime values.
Important: Using a Hierarchical Partition Key requires a container that uses hierarchical partition keys, read more.
For instance, the shape of the following entity:
import { CosmosDateTime, CosmosPartitionKey } from '@nestjs/azure-database';
import { PartitionKeyDefinitionVersion, PartitionKeyKind } from '@azure/cosmos';
@CosmosPartitionKey({
paths: ['/name', '/type/label'],
version: PartitionKeyDefinitionVersion.V2,
kind: PartitionKeyKind.MultiHash,
})
export class Event {
id?: string;
name: string;
type: {
label: string;
};
@CosmosDateTime() createdAt: Date;
}Will be automatically converted to:
{
"name": "NestJS Meetup",
"type": {
"label": "Meetup"
},
"createdAt": "2019-11-15T17:05:25.427Z"
}- Import the
AzureCosmosDbModuleinside your Nest feature moduleevent.module.ts:
import { AzureCosmosDbModule } from '@nestjs/azure-database';
import { Module } from '@nestjs/common';
import { Event } from './event.entity';
@Module({
imports: [
AzureCosmosDbModule.forRoot({
dbName: process.env.AZURE_COSMOS_DB_NAME,
endpoint: process.env.AZURE_COSMOS_DB_ENDPOINT,
key: process.env.AZURE_COSMOS_DB_KEY,
retryAttempts: 1,
}),
AzureCosmosDbModule.forFeature([{ dto: Event }]),
],
})
export class EventModule {}- Create a service that will abstract the CRUD operations:
$ nest generate service event- Use the
@InjectModel(Event)to get an instance of the Azure Cosmos DB Container for the entity definition created earlier:
import { InjectModel } from '@nestjs/azure-database';
import type { Container } from '@azure/cosmos';
import { Injectable } from '@nestjs/common';
import { Event } from './event.entity';
@Injectable()
export class EventService {
constructor(
@InjectModel(Event)
private readonly eventContainer: Container,
) {}
}@InjectModel(Event) will inject an Azure Cosmos DB Container instance for the Event entity. The Container provides a list of public methods for managing the database.
IMPORTANT: Please note that the Container instance is not a NestJS repository. It is the actual instance provided by the official Azure Cosmos DB SDK.
async create(eventDto: EventDTO): Promise<Event> {
const { resource } = await this.eventContainer.items.create<Event>(
eventDto,
);
return resource;
}Fetches all the results of the query.
async getEvents(): Promise<Event[]> {
const querySpec = {
query: 'SELECT * FROM events',
};
const { resources } = await this.eventContainer.items
.query<Event>(querySpec)
.fetchAll();
return resources;
}Fetch a single resource.
async getEvent(id: string, partitionKey: string | string[]): Promise<Event> {
const { resource } = await this.eventContainer
.item(id, type)
.read<Event>();
return resource;
}Replaces an item in the database.
async updateEvent(
id: string,
partitionKey: string | string[],
eventData: EventDTO,
): Promise<Event> {
let { resource: item } = await this.eventContainer
.item(id, type)
.read<Event>();
item = {
...item,
...eventData,
};
const { resource: replaced } = await this.eventContainer
.item(id, type)
.replace(item);
return replaced;
}Deletes an item from the database.
async deleteEvent(id: string, partitionKey: string | string[]): Promise<Event> {
const { resource: deleted } = await this.eventContainer
.item(id, type)
.delete<Event>();
return deleted;
}If using hierarchical partition keys, you need to provide the partition key as an array of strings when calling one of the CRUD methods on the Container. For example, when reading a single resource:
this.eventContainer
.item("1234", ['foo', 'bar'])
.read<Event>();Read more about Hierarchical Partition Keys.
- Create or update your existing
.envfile with the following content:
AZURE_STORAGE_CONNECTION_STRING=
-
IMPORTANT: Make sure to add your
.envfile to your .gitignore! The.envfile MUST NOT be versioned on Git. -
Make sure to include the following call to your
main.tsfile:
if (process.env.NODE_ENV !== 'production') require('dotenv').config();This line must be added before any other imports!
- The
AzureTableStorageModulewill automatically read theAZURE_STORAGE_CONNECTION_STRINGenvironment variable and use it to connect to your Azure Storage account.
Check out the Table Storage example project included in the sample folder
- Create a new feature module, eg. with the nest CLI:
$ nest generate module event- Create a Data Transfer Object (DTO) inside a file named
event.dto.ts:
export class EventDTO {
name: string;
type: string;
}- Create a file called
event.entity.tsand describe the entity model using plain JavaScript objects. The only requirement is to provide apartitionKeyand arowKeyproperties. For instance, the shape of the following entity:
export class Event {
partitionKey: string; // required
rowKey: string; // required
name: string;
type: string;
}- Import the
AzureTableStorageModuleinside your Nest feature moduleevent.module.ts:
import { Module } from '@nestjs/common';
import { AzureTableStorageModule } from '@nestjs/azure-database';
@Module({
imports: [AzureTableStorageModule.forFeature(Event)],
})
export class EventModule {}You can optionally pass in the following arguments:
import { Module } from '@nestjs/common';
import { AzureTableStorageModule } from '@nestjs/azure-database';
@Module({
imports: [
AzureTableStorageModule.forFeature(Event, {
table: 'foobar',
createTableIfNotExists: true,
}),
],
})
export class EventModule {}table: string: The name of the table. If not provided, the name of theEvententity will be used as a table namecreateTableIfNotExists: boolean: Whether to automatically create the table if it doesn't exists or not:- If
truethe table will be created during the startup of the app. - If
falsethe table will not be created. You will have to create the table by yourself before querying it!
- If
- Create a service that will abstract the CRUD operations:
$ nest generate service event- Use the
@InjectRepository(Event)to get an instance of the AzureRepositoryfor the entity definition created earlier:
import { InjectRepository, Repository } from '@nestjs/azure-database';
import { Injectable } from '@nestjs/common';
import { Event } from './event.entity';
@Injectable()
export class EventService {
constructor(
@InjectRepository(Event)
private readonly eventRepository: Repository<Event>,
) {}
}The AzureTableStorageRepository provides a list of public methods for managing various CRUD operations:
create(entity: T): Promise<T | null>: creates a new entity.
async create(event: Event): Promise<Event> {
return await this.eventRepository.create(event);
}find(partitionKey: string, rowKey: string): Promise<T>: finds one entity using its partitionKey and rowKey.
async find(partitionKey: string, rowKey: string): Promise<Event> {
return await this.eventRepository.find(partitionKey, rowKey);
}findAll(options: { queryOptions?: TableEntityQueryOptions }): Promise<T[]>: finds all entities.
async findAll(options: { queryOptions?: TableEntityQueryOptions }): Promise<Event[]> {
return await this.eventRepository.findAll();
}update(partitionKey: string, rowKey: string, entity: T): Promise<T>: Updates an entity using a "merge" strategy.
async update(
partitionKey: string,
rowKey: string,
event: Event,
): Promise<Event> {
return await this.eventRepository.update(partitionKey, rowKey, event);
}delete(partitionKey: string, rowKey: string): Promise<DeleteTableEntityResponse>: Removes an entity from the table.
async delete(partitionKey: string, rowKey: string): Promise<void> {
await this.eventRepository.delete(partitionKey, rowKey);
}Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please read more here.
- Author - Wassim Chegham
- Website - https://wassim.dev
- Twitter - @manekinekko
Nest is MIT licensed.