Introduzindo MongoDB no CrazyStack Node.js
Nesta aula, você aprenderá sobre a introdução ao MongoDB. Veremos uma classe de helper para acessar o banco de dados MongoDB que fornece funções para conectar e desconectar do banco de dados, recuperar uma coleção específica, remover a senha de um objeto da coleção, remover a senha de vários objetos da coleção, iniciar e finalizar uma sessão no MongoDB e recuperar a sessão atual. Essa classe ajudará na gestão das conexões com o banco de dados e na realização de operações de consulta de forma simples e eficiente.
import { MongoClient, Collection } from "mongodb";
export const MongoHelper = {
client: null as unknown as MongoClient | any,
uri: null as unknown as string,
session: null as unknown as any,
async connect(connectionUrl: string) {
this.uri = connectionUrl;
this.client = await MongoClient.connect(connectionUrl, {
retryReads: true,
retryWrites: true,
});
return this?.client?.connect?.();
},
async disconnect() {
if (this?.client) {
await this.endSession();
await this.client.close();
this.client = null;
}
},
async getCollection(name: string): Promise<Collection> {
if (!this.client) {
await this.connect(this.uri);
}
return this?.client?.db?.()?.collection?.(name);
},
mapPassword(collection: any): any {
return { ...collection, password: null };
},
mapCollectionPassword(collection: any[]): any[] {
return collection?.map?.((coll) => MongoHelper.mapPassword(coll));
},
async startSession() {
const session = await this?.client?.startSession?.();
this.session = session;
return session;
},
async getSession() {
return this.session;
},
async endSession() {
if (this.session) {
await this.session.endSession();
}
this.session = null;
},
};
O código acima é uma classe de helper para acesso ao banco de dados MongoDB. Ele fornece funções para conectar e desconectar do banco de dados, recuperar uma coleção específica, remover a senha de um objeto da coleção, remover a senha de vários objetos da coleção, iniciar e finalizar uma sessão no MongoDB e recuperar a sessão atual. Ele também armazena o cliente Mongo, a URI de conexão e a sessão atual como variáveis de instância.
import {
mapAnyToMongoObject,
mapQueryParamsToQueryMongo,
MongoHelper,
} from "@/application/infra/database/mongodb";
import { Repository } from "@/application/infra/contracts/repository";
import { Collection, ObjectId } from "mongodb";
export class MongoRepository extends Repository {
public collectionName: string;
constructor(collectionName: string) {
super();
this.collectionName = collectionName;
}
private async getCollection(): Promise<Collection> {
return MongoHelper.getCollection(this.collectionName);
}
async insertOne(data: any): Promise<any> {
const collection = await this.getCollection();
const session = await MongoHelper.getSession();
return collection.insertOne(mapAnyToMongoObject(data), { session });
}
async add(data: any): Promise<any> {
const collection = await this.getCollection();
const session = await MongoHelper.getSession();
const { insertedId } = (await this.insertOne(data)) || {};
if (!!insertedId) {
const objInserted = await collection.findOne(
{ _id: new ObjectId(insertedId) },
{ session }
);
return MongoHelper.mapPassword(objInserted);
}
return null;
}
async updateOne(query: any, data: any): Promise<any> {
const collection = await this.getCollection();
const session = await MongoHelper.getSession();
if (query._id) {
query._id = new ObjectId(query._id);
}
return collection.updateOne(
mapQueryParamsToQueryMongo(query),
{ $set: mapAnyToMongoObject(data) },
{ upsert: false, session }
);
}
async update(query: any, data: any): Promise<any> {
const collection = await this.getCollection();
const session = await MongoHelper.getSession();
const result = await this.updateOne(query, data);
if (result?.modifiedCount === 1) {
return collection.findOne(mapQueryParamsToQueryMongo(query), { session });
}
return null;
}
async incrementOne(query: any, data: any): Promise<any> {
const collection = await this.getCollection();
const session = await MongoHelper.getSession();
if (query._id) {
query._id = new ObjectId(query._id);
}
return collection.updateOne(
mapQueryParamsToQueryMongo(query),
{ $inc: mapAnyToMongoObject(data) },
{ upsert: false, session }
);
}
async increment(query: any, data: any): Promise<any> {
const collection = await this.getCollection();
const session = await MongoHelper.getSession();
const result = await this.incrementOne(query, data);
if (result?.modifiedCount === 1) {
return collection.findOne(mapQueryParamsToQueryMongo(query), { session });
}
return null;
}
async deleteOne(query: any): Promise<any> {
const collection = await this.getCollection();
const session = await MongoHelper.getSession();
if (query._id) {
query._id = new ObjectId(query._id);
}
const result = (await collection.deleteOne(mapQueryParamsToQueryMongo(query), {
session,
})) as any;
if (result?.deletedCount === 1) {
return true;
}
return false;
}
async getOne(query: any, options?: any): Promise<any> {
const collection = await this.getCollection();
const session = await MongoHelper.getSession();
if (query?._id) {
query._id = new ObjectId(query._id);
}
return collection.findOne(mapQueryParamsToQueryMongo(query), {
...options,
session,
});
}
async getAll(query: any): Promise<any> {
const collection = await this.getCollection();
const session = await MongoHelper.getSession();
return collection.find(mapQueryParamsToQueryMongo(query), { session }).toArray();
}
async getPaginate(
page: number,
query: any,
sort: any,
limit: number,
projection: any
): Promise<any> {
const collection = await this.getCollection();
const session = await MongoHelper.getSession();
if (query._id) {
query._id = new ObjectId(query._id);
}
return collection
.find(mapQueryParamsToQueryMongo(query), { session })
.project(projection)
.skip((page - 1) * limit)
.limit(limit)
.sort(sort)
.toArray();
}
async getCount(query: any): Promise<any> {
const collection = await this.getCollection();
if (query._id) {
query._id = new ObjectId(query._id);
}
return collection.countDocuments(mapQueryParamsToQueryMongo(query));
}
async aggregate(query: any): Promise<any> {
const collection = await this.getCollection();
const session = await MongoHelper.getSession();
return collection.aggregate(query, { session }).toArray();
}
}
Este é um código de uma classe chamada "MongoRepository" que herda de uma classe chamada "Repository". Esta classe fornece uma estrutura básica para acessar e manipular dados armazenados em um banco de dados MongoDB. Ele contém métodos para inserir, atualizar, excluir e recuperar dados, bem como métodos para paginação, contagem e agregação de dados. Ele também usa outras classes para ajudar a mapear os dados entre o aplicativo e o banco de dados, e para gerenciar a conexão com o banco de dados.
Em breve
Em breve no curso vocês entenderão o poder de utilizar essa classe abstrata Repository. Por exemplo, caso queiramos usar um ORM como o prisma poderíamos fazer um PrismaRepository:
import { PrismaClient } from '@prisma/client'
import { Repository } from '@/application/infra/contracts/repository'
export class PrismaRepository extends Repository {
private prisma: PrismaClient
constructor() {
super()
this.prisma = new PrismaClient()
}
async insertOne(data: any): Promise<any> {
return this.prisma.create(this.collectionName, data)
}
async add(data: any): Promise<any> {
return this.prisma.create(this.collectionName, data)
}
async updateOne(query: any, data: any): Promise<any> {
return this.prisma.update(this.collectionName, { data, where: query })
}
async update(query: any, data: any): Promise<any> {
const result = await this.updateOne(query, data)
if (result) {
return this.getOne(query)
}
return null
}
async deleteOne(query: any): Promise<any> {
return this.prisma.delete(this.collectionName, { where: query })
}
async getOne(query: any, options?: any): Promise<any> {
return this.prisma.findOne(this.collectionName, { where: query, ...options })
}
async getAll(query: any): Promise<any> {
return this.prisma.findMany(this.collectionName, { where: query })
}
async getPaginate(
page: number,
query: any,
sort: any,
limit: number,
projection: any
): Promise<any> {
const skip = (page - 1) * limit
return this.prisma.findMany(this.collectionName, {
where: query,
skip,
take: limit,
orderBy: sort,
select: projection,
})
}
async getCount(query: any): Promise<any> {
return this.prisma.count(this.collectionName, { where: query })
}
async aggregate(query: any): Promise<any> {
// Not supported by Prisma
return null
}
}
Ou um SupaBaseRepository
import { Repository } from "@/application/infra/contracts/repository";
import { Supabase } from "@supabase/supabase-js";
export class SupabaseRepository extends Repository {
private supabase: Supabase;
constructor(supabase: Supabase) {
super();
this.supabase = supabase;
}
async insertOne(tableName: string, data: any): Promise<any> {
return this.supabase.from(tableName).insert(data).one();
}
async add(tableName: string, data: any): Promise<any> {
const result = await this.insertOne(tableName, data);
if (result?.inserted_id) {
return this.supabase
.from(tableName)
.select("*")
.where({ id: result.inserted_id })
.one();
}
return null;
}
async updateOne(tableName: string, query: any, data: any): Promise<any> {
return this.supabase
.from(tableName)
.update(data)
.where(query)
.returning("*")
.one();
}
async update(tableName: string, query: any, data: any): Promise<any> {
const result = await this.updateOne(tableName, query, data);
if (result) {
return result;
}
return null;
}
async deleteOne(tableName: string, query: any): Promise<boolean> {
const result = await this.supabase
.from(tableName)
.delete()
.where(query)
.returning("*")
.one();
if (result) {
return true;
}
return false;
}
async getOne(tableName: string, query: any): Promise<any> {
return this.supabase
.from(tableName)
.select("*")
.where(query)
.one();
}
///resto
}