Screenshot 2020 10 20 at 9.29.47 PM

Se você tem muito pouca experiência com Node.js / JavaScript ou o back-end em geral, este é provavelmente um bom lugar para começar. Você também pode encontrar um curso grátis sobre Mongoose + MongoDB + Node.js aqui. Vamos mergulhar.

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”, neste caso denominado driver MongoDB. 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 de você – mas isso só o leva até o ponto em que um desenvolvedor.

Como o MongoDB é um banco de dados sem esquema, ele oferece muito mais poder do que você precisa como um iniciante. Mais potência significa mais área de superfície para errar. Você precisa reduzir sua área de superfície 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 (o pacote npm que mencionei acima).

A regra geral com abstrações (do jeito que eu entendo) é 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.

Uma boa maneira de pensar sobre isso é tecnicamente criar um aplicativo de bate-papo em tempo real tanto em C quanto em Python.

O exemplo do Python seria muito mais fácil e rápido para você como desenvolvedor implementar com maior produtividade.

C poderia ser mais eficiente, mas terá um custo enorme em produtividade / velocidade de desenvolvimento / bugs / travamentos. Ademais, na maior parte, você não precisa ter o poder que C lhe dá para implementar websockets.

Da mesma forma, com o Mongoose, você pode limitar sua área de superfície de acesso à API de nível inferior, mas desbloquear muitos ganhos potenciais e bom DX.

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 você gostar.

Como realizar operações Mongoose

Vamos agora discutir rapidamente as operações com o Mongoose e como você deve executá-las.

O Mongoose oferece opções para duas coisas:

  1. Consulta baseada em cursor
  2. Buscando consulta completa

Consulta baseada em cursor

A consulta baseada em cursor significa que você trabalha com um único registro por vez, enquanto busca um único ou um lote de documentos por vez no banco de dados. Esta é uma maneira eficiente de trabalhar com grandes quantidades de dados em um ambiente de memória limitada.

Imagine que você precise analisar documentos de 10 GB de tamanho total em um servidor de nuvem de 1 GB / 1 núcleo. Você não pode buscar a coleção inteira porque ela não caberá em seu sistema. O cursor é uma boa (e única?) Opção aqui.

Consulta de busca completa

Este é o tipo de consulta em que você obtém a resposta completa de sua consulta de uma só vez. Na maior parte, é isso que você usará. Portanto, vamos nos concentrar principalmente neste método aqui.

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

Este é um exemplo reduzido diretamente da base de código do codedamn. Algumas coisas interessantes que você deve observar aqui:

  1. Tente manter required: true em todos os campos que são 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. Ademais, a validação gratuita também é muito legal.
  2. Defina índices e campos exclusivos. unique propriedade também pode ser adicionada em um esquema. Os índices são um tópico amplo, então não vou me aprofundar aqui. Mas 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 (Completed aqui, 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 Create, Read, vocêpdate e Delete. 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 (bom para os olhos, sem benefícios de desempenho inovadores como tal)
  2. Use blocos try-catch em torno das consultas porque sua consulta pode falha por vários motivos (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).lean()

  1. Você pode ver o lean() chamada de função lá? É muito útil para o desempenho. Por padrão, o Mongoose processa o (s) documento (s) retornado (s) do banco de dados e adiciona seus mágico métodos nele (por exemplo .save)
  2. Quando você usa .lean(), O Mongoose retorna objetos JSON simples em vez de documentos com muitos recursos e memória. Também torna as consultas mais rápidas e econômicas em sua CPU.
  3. No entanto, você pode omitir .lean() se você está realmente pensando em atualizar os dados (veremos isso a seguir)

A operação de atualização

Se você já tem um documento Mongoose com você (sem disparar com .lean()), você pode simplesmente 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á ligado findOne e o segundo está ligado 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).

No outro caso, você pode usar uma consulta como esta:

const res = await CompletedSchema.updateOne(<condition>, <query>).lean()

e ele fará apenas uma única chamada para o banco de dados.

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>)

Assim como updateOne, deleteOne também aceita o primeiro argumento como a condição de correspondência para o documento.

Também existe outro método chamado deleteMany que deve ser usado apenas quando você sabe que deseja excluir vários documentos.

Em qualquer outro caso, sempre use deleteOne para 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.

Se você gostou deste artigo, pode aprimorar seu jogo ainda mais como desenvolvedor seguindo o caminho de aprendizagem de backend codedamn. Sinta-se à vontade para entrar em contato comigo no Twitter para qualquer feedback!