Como usar MongoDB + Mongoose com Node.js

O MongoDB é, sem dúvida, uma das opções de banco de dados NoSQL mais populares da atualidade. E tem uma grande comunidade e ecossistema.

Por que você precisa do Mongoose?

Para entender por que precisamos do Mongoose, vamos entender como o MongoDB (e um banco de dados) funciona no nível de arquitetura.

  • Você tem um servidor de banco de dados (servidor da comunidade MongoDB, por exemplo)
  • Você tem um script Node.js em execução (como um processo)

O servidor MongoDB escuta em um soquete TCP (geralmente) e seu processo Node.js pode se conectar a ele usando uma conexão TCP.

Mas, além do TCP, o MongoDB também tem seu próprio protocolo para entender o que exatamente o cliente (nosso processo Node.js) deseja que o banco de dados faça.

Para esta comunicação, em vez de aprendermos as mensagens que temos que enviar na camada TCP, abstraímos isso com a ajuda de um software "driver", chamado de driver MongoDB neste caso. O driver MongoDB está disponível como um pacote npm aqui .

Agora lembre-se, o driver MongoDB é responsável por conectar e abstrair as solicitações / respostas de comunicação de baixo nível entre você (desenvolvedor) e o banco de dados (MongoDB).

Como o MongoDB é um banco de dados sem esquema, ele oferece muito mais poder do que você precisa para a maioria dos casos. Mais recursos significa mais possibilidades para errar. Você precisa reduzir sua área de chances de bugs e erros que você pode fazer em seu código. Você precisa de algo mais.

Conheça o Mongoose. Mongoose é uma abstração do driver nativo MongoDB.

A regra geral com abstrações (na maioria das vezes) é que com cada abstração você perde algum poder de operação de baixo nível. Mas isso não significa necessariamente que seja ruim. Às vezes, aumenta a produtividade em 1000x + porque você nunca precisa realmente ter acesso total à API subjacente.

Com o Mongoose, você pode limitar sua área de superfície de acesso à API de nível inferior, mas desbloquear muitos ganhos potenciais.

Como conectar Mongoose + MongoDB

Em primeiro lugar, vamos ver rapidamente como você deve se conectar ao seu banco de dados MongoDB em 2020 com o Mongoose:

mongoose.connect(DB_CONNECTION_STRING, {
	useNewUrlParser: true,
	useUnifiedTopology: true,
	useCreateIndex: true,
	useFindAndModify: false
})

Este formato de conexão garante que você esteja usando o novo analisador de URL do Mongoose e que não esteja usando nenhuma prática obsoleta. Você pode ler em detalhes sobre todas essas mensagens de suspensão de uso aqui, se desejar.

Como usar modelos Mongoose

Os modelos são a superpotência do Mongoose. Eles ajudam a impor regras de "esquema" e fornecem uma integração perfeita do código do Node nas chamadas do banco de dados.

O primeiro passo é definir um bom modelo:

import mongoose from 'mongoose'

const CompletedSchema = new mongoose.Schema(
	{
		type: { type: String, enum: ['course', 'classroom'], required: true },
		parentslug: { type: String, required: true },
		slug: { type: String, required: true },
		userid: { type: String, required: true }
	},
	{ collection: 'completed' }
)

CompletedSchema.index({ slug: 1, userid: 1 }, { unique: true })

const model = mongoose.model('Completed', CompletedSchema)
export default model

Algumas coisas interessantes que você deve observar aqui:

  1. Tente manter required: truetodos os campos obrigatórios. Isso pode ser um grande alívio para você se você não usar um sistema de verificação de tipo estático como o TypeScript para ajudá-lo com os nomes de propriedade corretos ao criar um objeto. Além disso, a validação também é muito legal.
  2. Defina índices e campos exclusivos. uniquepropriedade também pode ser adicionada em um esquema. Em grande escala, eles podem realmente ajudá-lo a acelerar muito suas consultas.
  3. Defina um nome de coleção explicitamente. Embora o Mongoose possa fornecer automaticamente um nome de coleção com base no nome do modelo ( Completedaqui, por exemplo), isso é abstração demais na minha opinião. Você deve pelo menos saber sobre os nomes e coleções de seu banco de dados em sua base de código.
  4. Restrinja os valores se puder, usando enums.

Como realizar operações CRUD

CRUD significa C reate, R ead, U pdate e D elete. Estas são as quatro opções fundamentais com as quais você pode executar qualquer tipo de manipulação de dados em um banco de dados. Vamos ver rapidamente alguns exemplos dessas operações.

A Operação Criar

Isso significa simplesmente criar um novo registro em um banco de dados. Vamos usar o modelo que definimos acima para criar um registro:

try {
    const res = await CompletedSchema.create(record)
} catch(error) {
	console.error(error)
    // handle the error
}

Novamente, algumas dicas aqui:

  1. Use async-await em vez de callbacks
  2. Use blocos try-catch em torno das chamadas porque sua chamada pode falhar por uma série de razões (registro duplicado, valor incorreto e assim por diante)

A operação de leitura

Isso significa ler os valores existentes no banco de dados. é simples como parece, mas existem algumas pegadinhas que você deve saber com o Mongoose:

const res = await CompletedSchema.find(info)

A operação de atualização

Se você já tem um documento Mongoose com você (obtido com o método .find() por exemplo), você pode simplesmente ir em frente e modificar a propriedade do objeto e salvá-lo usando object.save():

const doc = await CompletedSchema.findOne(info)
doc.slug = 'something-else'
await doc.save()

Lembre-se de que aqui são feitas duas chamadas ao banco de dados. O primeiro está chamando findOnee o segundo está chamando doc.save.

Se possível, você deve sempre reduzir o número de solicitações que chegam ao banco de dados (porque se você estiver comparando memória, rede e disco, a rede é quase sempre a mais lenta).

A operação de exclusão

Excluir também é simples com o Mongoose. Vamos ver como você pode excluir um único documento:

const res = await CompletedSchema.deleteOne(<condition>)

Da mesma forma updateOne, deleteOnetambém aceita o primeiro argumento como condição de correspondência para o documento.

Há também outro método chamado deleteManyque deve ser usado apenas quando você sabe que deseja excluir vários documentos.

Em qualquer outro caso, use sempre deleteOnepara evitar múltiplas exclusões acidentais, especialmente quando você está tentando executar consultas por conta própria.

Conclusão

Este artigo foi uma introdução simples ao mundo Mongoose e MongoDB para desenvolvedores Node.js.

Meu objetivo foi mostrar de forma simples como é fácil começar a utilizar o Mongoose e ganhar performace como desenvolvedor.

Ficou com dúvida? fique a vontate para me contar nos comentários.

Este artigo foi traduzido e baseado neste post.