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
.env
file with the following content:
AZURE_COSMOS_DB_NAME=
AZURE_COSMOS_DB_ENDPOINT=
AZURE_COSMOS_DB_KEY=
-
IMPORTANT: Make sure to add your
.env
file to your .gitignore! The.env
file MUST NOT be versioned on Git. -
Make sure to include the following call to your
main.ts
file:
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.ts
and describe the entity model using the provided decorators:
-
@CosmosPartitionKey(value: string | HierarchicalPartitionKey)
: Represents thePartitionKey
orHierarchicalPartitionKey
of 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
AzureCosmosDbModule
inside 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
.env
file with the following content:
AZURE_STORAGE_CONNECTION_STRING=
-
IMPORTANT: Make sure to add your
.env
file to your .gitignore! The.env
file MUST NOT be versioned on Git. -
Make sure to include the following call to your
main.ts
file:
if (process.env.NODE_ENV !== 'production') require('dotenv').config();
This line must be added before any other imports!
- The
AzureTableStorageModule
will automatically read theAZURE_STORAGE_CONNECTION_STRING
environment 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.ts
and describe the entity model using plain JavaScript objects. The only requirement is to provide apartitionKey
and arowKey
properties. For instance, the shape of the following entity:
export class Event {
partitionKey: string; // required
rowKey: string; // required
name: string;
type: string;
}
- Import the
AzureTableStorageModule
inside 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 theEvent
entity will be used as a table namecreateTableIfNotExists: boolean
: Whether to automatically create the table if it doesn't exists or not:- If
true
the table will be created during the startup of the app. - If
false
the 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 AzureRepository
for 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(): Promise<T[]>
: finds all entities (NOTE: odata filters are not supported yet).
async findAll(): 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.