Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Learn why MongoDB was selected as a leader in the 2024 Gartner® Magic Quadrant™
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Idiomaschevron-right
JavaScriptchevron-right

Introdução ao MongoDB e Mongoose

Jesse Hall9 min read • Published Apr 07, 2022 • Updated Aug 05, 2024
MongoDBJavaScript
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Início rápido
star-empty
star-empty
star-empty
star-empty
star-empty
Neste artigo, aprenderemos como o Mongoose, uma biblioteca de terceiros para o MongoDB, pode ajudar você a estruturar e acessar seus dados com facilidade.

O que é o Mongoose?

Muitos que aprendem MongoDB são apresentados a ele por meio da biblioteca muito popular Mongoose, que é descrita como “elegant MongoDB object modeling for Node.js.
Mongoose é uma biblioteca ODM (Object Data Modeling) para MongoDB. Embora você não precise usar uma ferramenta ODM ou ORM (Object Relational Mapping) para ter uma ótima experiência com o MongoDB, alguns desenvolvedores as preferem. Muitos desenvolvedores Node.js optam por trabalhar com o Mongoose para ajudar com modelagem de dados, imposição de esquema, validação de modelo e manipulação de dados em geral. E o Mongoose simplifica essas tarefas.
Se quiser ouvir o mantenedor do Mongoose, Val Karpov, ouça este episódio do MongoDB Podcast !

Por que o Mongoose?

Por padrão, o MongoDB tem um modelo de dados flexível. Isso torna os bancos de dados do MongoDB muito fáceis de alterar e atualizar no futuro. Mas muitos desenvolvedores estão acostumados a ter esquemas rígidos.
O Mongoose força um esquema semirrígido desde o início. Com o Mongoose, os desenvolvedores devem definir um esquema e um modelo.

O que é um esquema?

Um esquema define a estrutura dos documentos da sua coleção. Um esquema Mongoose é mapeado diretamente para uma coleção MongoDB.
1const blog = new Schema({
2 title: String,
3 slug: String,
4 published: Boolean,
5 author: String,
6 content: String,
7 tags: [String],
8 createdAt: Date,
9 updatedAt: Date,
10 comments: [{
11 user: String,
12 content: String,
13 votes: Number
14 }]
15});
Com esquemas, definimos cada campo e seu tipo de dados. Tipos permitidos são:
  • String
  • Número
  • Data
  • Buffer
  • Boolean
  • Misto
  • ObjectId
  • Array
  • Decimal128
  • Map

O que é um modelo?

Os modelos pegam seu esquema e o aplicam a cada documento em sua coleção.
Os modelos são responsáveis por todas as interações de documentos, como criação, leitura, atualização e exclusão (CRUD).
Uma observação importante: o primeiro argumento passado para o modelo deve ser a forma singular do nome da sua coleção. O Mongoose altera automaticamente isso para o plural, transforma em minúsculas e usa para o nome da coleção de banco de dados.
1const Blog = mongoose.model('Blog', blog);
Neste exemplo, Blog se traduz na coleção blogs.

Configuração do ambiente

Vamos configurar nosso ambiente. Presumo que você já tenha o Node.js instalado.
Vamos executar os seguintes comandos do terminal para começar:
1mkdir mongodb-mongoose
2cd mongodb-mongoose
3npm init -y
4npm i mongoose
5npm i -D nodemon
6code .
Isso cria o diretório do projeto, inicializa, instala os pacotes necessários e abre o projeto no VS Code.
Vamos adicionar um script ao nosso arquivo package.json para executar nosso projeto. Também usaremos ES Modules em vez de Common JS, portanto, adicionaremos o módulo typetambém. Isso também nos permitirá usarawait de nível superior .
1...
2 "scripts": {
3 "dev": "nodemon index.js"
4 },
5 "type": "module",
6...

Conectando ao MongoDB

Agora criaremos o arquivo index.js e usaremos o Mongoose para nos conectar ao MongoDB.
1import mongoose from 'mongoose'
2
3mongoose.connect("mongodb+srv://<username>:<password>@cluster0.eyhty.mongodb.net/myFirstDatabase?retryWrites=true&w=majority")
Você pode se conectar a uma instância local do MongoDB, mas, neste artigo, usaremos um cluster MongoDB Atlas gratuito. Se você ainda não tiver uma conta, é fácil se cadastrar para um cluster MongoDB Atlas gratuito aqui.
E se você ainda não tiver um cluster configurado, siga nosso guia para criar seu cluster.
Depois de criar seu cluster, você deve substituir a string de conexão acima pela sua string de conexão, incluindo seu nome de usuário e senha.
A string de conexão que você copia do dashboard do MongoDB Atlas fará referência ao banco de dados do myFirstDatabase. Mude isso para o que você gostaria de chamar de banco de dados.

Criar um esquema e um modelo

Antes de fazermos qualquer coisa com nossa conexão, precisaremos criar um esquema e um modelo.
O ideal é criar um arquivo de esquema/modelo para cada esquema necessário. Então, criaremos uma nova estrutura de pasta/arquivo: model/Blog.js.
1import mongoose from 'mongoose';
2const { Schema, model } = mongoose;
3
4const blogSchema = new Schema({
5 title: String,
6 slug: String,
7 published: Boolean,
8 author: String,
9 content: String,
10 tags: [String],
11 createdAt: Date,
12 updatedAt: Date,
13 comments: [{
14 user: String,
15 content: String,
16 votes: Number
17 }]
18});
19
20const Blog = model('Blog', blogSchema);
21export default Blog;

Inserindo dados // método 1

Agora que temos nosso primeiro modelo e esquema configurados, podemos começar a inserir dados em nosso banco de dados.
De volta ao arquivo index.js, vamos inserir um novo artigo no blog.
1import mongoose from 'mongoose';
2import Blog from './model/Blog';
3
4mongoose.connect("mongodb+srv://mongo:mongo@cluster0.eyhty.mongodb.net/myFirstDatabase?retryWrites=true&w=majority")
5
6// Create a new blog post object
7const article = new Blog({
8 title: 'Awesome Post!',
9 slug: 'awesome-post',
10 published: true,
11 content: 'This is the best post ever',
12 tags: ['featured', 'announcement'],
13});
14
15// Insert the article in our MongoDB database
16await article.save();
Primeiro precisamos importar o modelo Blog que criamos. Em seguida, criamos um novo objeto e usamos o método save() para inseri-lo em nosso MongoDB database.
Vamos adicionar um pouco mais depois disso para registrar o que está atualmente no banco de dados. Usaremos o método findOne() para isso.
1// Find a single blog post
2const firstArticle = await Blog.findOne({});
3console.log(firstArticle);
Vamos executar o código!
1npm run dev
Você deverá ver o documento inserido registrado em seu terminal.
Como estamos usando nodemon neste projeto, toda vez que você salvar um arquivo, o código será executado novamente. Se você quiser inserir vários artigos, continue salvando. 😄

Inserindo dados // método 2

No exemplo anterior, usamos o método save() Mongoose para inserir o documento em nosso banco de dados. Isso requer duas ações: instanciar o objeto e salvá-lo.
Como alternativa, podemos fazer isso em uma ação usando o método create() do Mongoose.
1// Create a new blog post and insert into database
2const article = await Blog.create({
3 title: 'Awesome Post!',
4 slug: 'awesome-post',
5 published: true,
6 content: 'This is the best post ever',
7 tags: ['featured', 'announcement'],
8});
9
10console.log(article);
Este método é muito melhor! Além de podermos inserir nosso documento, também retornamos o documento junto com seu _id quando o registramos no console.

Atualizar dados

O Mongoose também torna a atualização de dados muito conveniente. Expandindo o exemplo anterior, vamos alterar o title do nosso artigo.
1article.title = "The Most Awesomest Post!!";
2await article.save();
3console.log(article);
Podemos editar diretamente o objeto local e, em seguida, usar o método save() para gravar a atualização de volta no banco de dados. Acho que não há nada mais fácil do que isso!

Encontrar dados

Vamos garantir que estamos atualizando o documento correto. Usaremos um método especial do Mongoose, findById(), para obter nosso documento pelo seu ObjectId.
1const article = await Blog.findById("62472b6ce09e8b77266d6b1b").exec();
2console.log(article);
Observe que usamos a função exec() do Mongoose. Isso é opcional e retorna uma promessa. Na minha experiência, é melhor usar essa função, pois ela evitará alguns problemas de coçadura. Se quiser ler mais sobre isso, confira esta nota nos documentos do Mongoose sobre promessas.
Existem muitas opções de query no Mongoose. Veja a lista completa de queries.

Campos de projeção de documentos

Assim como no driver padrão do MongoDB Node.js, podemos projetar apenas os campos necessários. Vamos obter somente os campos title, slug e content.
1const article = await Blog.findById("62472b6ce09e8b77266d6b1b", "title slug content").exec();
2console.log(article);
O segundo parâmetro pode ser do tipo Object|String|Array<String> para especificar quais campos queremos projetar. Neste caso, usamos um String.

Excluindo dados

Assim como no driver padrão Node.js do MongoDB, temos os métodos deleteOne() e deleteMany().
1const blog = await Blog.deleteOne({ author: "Jesse Hall" })
2console.log(blog)
3
4const blog = await Blog.deleteMany({ author: "Jesse Hall" })
5console.log(blog)

Validação

Observe que os documentos que inserimos até agora não continham author, datas ou comments. Até agora, definimos como deve ser a estrutura de nosso documento, mas não definimos quais campos são realmente obrigatórios. Neste ponto, qualquer campo pode ser omitido.
Vamos definir alguns campos obrigatórios em nosso esquema Blog.js.
1const blogSchema = new Schema({
2 title: {
3 type: String,
4 required: true,
5 },
6 slug: {
7 type: String,
8 required: true,
9 lowercase: true,
10 },
11 published: {
12 type: Boolean,
13 default: false,
14 },
15 author: {
16 type: String,
17 required: true,
18 },
19 content: String,
20 tags: [String],
21 createdAt: {
22 type: Date,
23 default: () => Date.now(),
24 immutable: true,
25 },
26 updatedAt: Date,
27 comments: [{
28 user: String,
29 content: String,
30 votes: Number
31 }]
32});
Ao incluir validação em um campo, passamos um objeto como seu valor.
value: String é o mesmo que value: {type: String}.
Há vários métodos de validação que podem ser usados.
Podemos definir required como verdadeiro em quaisquer campos que gostaríamos que fossem necessários.
Para o slug, queremos que a string esteja sempre em letras minúsculas. Para isso, podemos definir lowercase como verdadeiro. Isso pegará a entrada do slug e a converterá em minúsculas antes de salvar o documento no banco de dados.
Para nossa data created, podemos definir a compra padrão usando uma função de seta. Também queremos que essa data não possa ser alterada posteriormente. Podemos fazer isso definindo immutable como true.
Os validadores são executados somente nos métodos de criação ou gravação.

Outros métodos úteis

O Mongoose usa muitos métodos padrão do MongoDB e introduz muitos métodos auxiliares extras que são abstraídos dos métodos regulares do MongoDB. A seguir, vamos falar sobre alguns deles.
exists()
O método exists() retorna null ou o ObjectId de um documento que corresponde à query fornecida.
1const blog = await Blog.exists({ author: "Jesse Hall" })
2console.log(blog)
where()
O Mongoose também tem seu próprio estilo de consultar dados. O método where() nos permite encadear e construir queries.
1// Instead of using a standard find method
2const blogFind = await Blog.findOne({ author: "Jesse Hall" });
3
4// Use the equivalent where() method
5const blogWhere = await Blog.where("author").equals("Jesse Hall");
6console.log(blogWhere)
Qualquer um desses métodos funciona. Use o que lhe parecer mais natural.
Você também pode encadear vários métodos where() para incluir até mesmo a query mais complicada.
select()
Para incluir projeção ao usar o método where(), encadeie o método select() após sua query.
1const blog = await Blog.where("author").equals("Jesse Hall").select("title author")
2console.log(blog)

Vários esquemas

É importante entender suas opções ao modelar dados.
Se você vem de um banco de dados relacional, está acostumado a ter tabelas separadas para todos os seus dados relacionados.
Geralmente, no MongoDB os dados acessados juntos devem ser armazenados juntos.
Você deve planejar isso com antecedência, se possível. Aninhe os dados no mesmo esquema quando fizer sentido.
Se você precisar de esquemas separados, o Mongoose facilita muito.
Vamos criar outro esquema para podermos ver como vários esquemas podem ser usados juntos.
Criaremos um novo arquivo, User.js, na pasta modelo.
1import mongoose from 'mongoose';
2const {Schema, model} = mongoose;
3
4const userSchema = new Schema({
5 name: {
6 type: String,
7 required: true,
8 },
9 email: {
10 type: String,
11 minLength: 10,
12 required: true,
13 lowercase: true
14 },
15});
16
17const User = model('User', userSchema);
18export default User;
Para email, estamos usando uma nova propriedade, minLength, para exigir um comprimento mínimo de caracteres para essa string.
Agora, faremos referência a esse novo modelo de usuário em nosso esquema de blog para author e comments.user.
1import mongoose from 'mongoose';
2const { Schema, SchemaTypes, model } = mongoose;
3
4const blogSchema = new Schema({
5 ...,
6 author: {
7 type: SchemaTypes.ObjectId,
8 ref: 'User',
9 required: true,
10 },
11 ...,
12 comments: [{
13 user: {
14 type: SchemaTypes.ObjectId,
15 ref: 'User',
16 required: true,
17 },
18 content: String,
19 votes: Number
20 }];
21});
22...
Aqui, definimos author e comments.user como SchemaTypes.ObjectId e adicionamos um ref, ou referência, ao modelo de usuário.
Isso nos permitirá "join" nossos dados um pouco mais tarde.
E não se esqueça de desestruturar SchemaTypes de mongoose na parte superior do arquivo.
Por último, vamos atualizar o arquivo index.js. Precisamos importar nosso novo modelo de usuário, criar um novo usuário e criar um novo artigo com o _id do novo usuário.
1...
2import User from './model/User.js';
3
4...
5
6const user = await User.create({
7 name: 'Jesse Hall',
8 email: 'jesse@email.com',
9});
10
11const article = await Blog.create({
12 title: 'Awesome Post!',
13 slug: 'Awesome-Post',
14 author: user._id,
15 content: 'This is the best post ever',
16 tags: ['featured', 'announcement'],
17});
18
19console.log(article);
Observe agora que há uma coleção users junto com a coleção blogs no MongoDB database.
Agora você verá apenas o usuário _id no campo do autor. Então, como obtemos todas as informações para o autor junto com o artigo?
Podemos usar o método populate() do Mongoose.
1const article = await Blog.findOne({ title: "Awesome Post!" }).populate("author");
2console.log(article);
Agora os dados do author estão preenchidos, ou "joined," nos dados article. O Mongoose realmente usa o método $lookup nos bastidores.

Middleware

No Mongoose, middleware são funções executadas antes e/ou durante a execução de funções assíncronas no nível do esquema.
Este é um exemplo. Vamos atualizar a data updated sempre que um artigo for salvo ou atualizado. Adicionaremos isso ao nosso modelo Blog.js.
1blogSchema.pre('save', function(next) {
2 this.updated = Date.now(); // update the date every time a blog post is saved
3 next();
4});
Em seguida, no arquivo index.js, encontraremos um artigo, atualizaremos o título e o salvaremos.
1const article = await Blog.findById("6247589060c9b6abfa1ef530").exec();
2article.title = "Updated Title";
3await article.save();
4console.log(article);
Observe que agora temos uma dataupdated!
Além de pre(), há também uma função de middleware mongoose post() .

Próximos passos

Acho que nosso exemplo aqui poderia usar outro esquema para comments. Tente criar esse esquema e testá-lo adicionando alguns usuários e comentários.
Há muitos outros métodos auxiliares excelentes do Mongoose que não são abordados aqui. Certifique-se de verificar a documentação oficial para obter referências e mais exemplos.

Conclusão

Acho ótimo que os desenvolvedores tenham muitas opções para conectar e manipular dados no MongoDB. Independentemente de você preferir o Mongoose ou os drivers padrão do MongoDB, no final, o que importa são os dados e o que é melhor para sua aplicação e para o seu caso de uso.
Entendo por que o Mongoose é popular para muitos desenvolvedores e acho que o usarei mais no futuro.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Início rápido
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Criar um backend de gerenciamento de mídia escalável: integrando Node.js, Armazenamento de blobs Azure e MongoDB


Nov 05, 2024 | 10 min read
Tutorial

Uma leve introdução às listas vinculadas com o MongoDB


Apr 02, 2024 | 13 min read
Tutorial

Como distribuir um aplicativo no Kubernetes com o MongoDB Atlas Operator


Aug 30, 2024 | 9 min read
Tutorial

Segurança de tipo com Prisma e MongoDB


Aug 09, 2024 | 4 min read
Sumário