Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIniciantecódigo testado

Documentos e coleções no MongoDB: estrutura e consultas

Aprenda como documentos BSON e coleções funcionam, consulte objetos e arrays e aplique validação de schema com o driver oficial do MongoDB.

Rodolfo Mori5 min de leitura

Um documento é o registro que o MongoDB guarda; uma coleção reúne documentos do mesmo contexto. Nesta lição, você vai criar a coleção livros, armazenar objetos e arrays, consultar campos internos e ver o banco recusar um estoque negativo.

Em termos técnicos, o documento é uma sequência de pares campo–valor codificada em BSON. Em termos práticos, ele se parece com o objeto que sua aplicação já usa, mas ganha identidade, tipos próprios e persistência no servidor.

O fichário ajuda, até onde ajuda

Pense no catálogo físico da Livraria Horizonte. Cada ficha descreve um livro; ela pode ter título, preço, estoque, etiquetas de categoria e um quadro com os dados da editora. O conjunto de fichas forma o fichário. No MongoDB, a ficha é o documento e o fichário é a coleção.

O campo _id é o código único escrito na ficha. categorias é uma lista de etiquetas. editora é um pequeno quadro incorporado na ficha. Essa imagem explica por que informações lidas juntas podem ficar juntas.

Mas uma coleção não é um móvel que o banco percorre sempre do começo ao fim. MongoDB usa índices, cache e planos de consulta. Além disso, uma ficha de papel não cresce indefinidamente; um documento também não deve receber um array sem limite só porque BSON aceita arrays. A analogia localiza as partes, não decide a modelagem por você.

Se esses nomes ainda estiverem soltos, volte ao guia de MongoDB, que separa servidor, database, coleção e driver antes de chegar ao código.

Prepare o mesmo laboratório

Use o MongoDB 8.0.28 local descrito no guia. Em uma pasta vazia, instale o driver oficial e execute arquivos .mjs com Node:

bash
npm init -y
npm install mongodb@7.5.0
added 12 packages

No início de documentos.mjs, conecte e recrie um database exclusivo. O dropDatabase() é destrutivo; aqui ele é aceitável porque o nome devclub_documentos pertence somente ao laboratório. Nunca troque esse nome por uma base real para “testar mais rápido”.

js
import { MongoClient } from "mongodb";

const uri = process.env.MONGODB_URI ?? "mongodb://127.0.0.1:27017";
const client = new MongoClient(uri);

await client.connect();
const db = client.db("devclub_documentos");
await db.dropDatabase();
console.log({ database: db.databaseName, estado: "limpo" });
{ database: 'devclub_documentos', estado: 'limpo' }

Ao terminar o arquivo, acrescente await client.close(). Em código de produção, prefira try/finally; aqui manteremos os passos próximos para enxergar o estado que cada operação cria.

Crie uma coleção que sabe o que recusar

Inserir num nome inexistente pode criar uma coleção automaticamente. Vamos criá-la de forma explícita porque precisamos de validação. $jsonSchema exige os três campos centrais e restringe o estoque a inteiro não negativo:

js
await db.createCollection("livros", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["titulo", "preco", "estoque"],
      properties: {
        titulo: { bsonType: "string" },
        preco: {
          bsonType: ["double", "int", "long", "decimal"],
          minimum: 0,
        },
        estoque: { bsonType: "int", minimum: 0 },
      },
    },
  },
});

console.log(await db.listCollections({}, { nameOnly: true }).toArray());
[ { name: 'livros', type: 'collection' } ]

bsonType fala a língua do banco. O número 39.9 enviado pelo Node chega como double; o inteiro pequeno 8 chega como int. Por isso preço aceita uma lista de tipos numéricos e estoque exige inteiro. Num sistema financeiro, defina uma convenção de centavos ou Decimal128 em vez de misturar tipos sem controle.

Validação não transforma MongoDB em banco relacional nem cria relacionamentos. Ela protege o formato de cada documento que entra ou muda na coleção.

Insira documentos com lista e objeto interno

insertMany() recebe um array de documentos. Os ids textuais tornam o laboratório repetível; se _id fosse omitido, o driver geraria ObjectId.

js
const livros = db.collection("livros");

const resultado = await livros.insertMany([
  {
    _id: "livro-1",
    titulo: "JavaScript do zero",
    preco: 39.9,
    estoque: 8,
    categorias: ["programação", "javascript"],
    editora: { nome: "Código Aberto", cidade: "São Paulo" },
  },
  {
    _id: "livro-2",
    titulo: "Node.js na prática",
    preco: 54.5,
    estoque: 5,
    categorias: ["programação", "node"],
    editora: { nome: "Código Aberto", cidade: "São Paulo" },
  },
  {
    _id: "livro-3",
    titulo: "Design para quem programa",
    preco: 46,
    estoque: 3,
    categorias: ["design", "interface"],
    editora: { nome: "Traço", cidade: "Recife" },
  },
]);

console.log({ inseridos: resultado.insertedCount });
{ inseridos: 3 }

Um documento pode não ter todos os campos do outro. A validação só exige os campos declarados em required. Isso é schema flexível, não ausência de schema: seu código, suas consultas e suas regras ainda pressupõem um formato.

Consulte um campo aninhado e um valor do array

Como encontrar livros de programação cuja editora fica em São Paulo? A notação editora.cidade atravessa o documento incorporado. Comparar categorias: "programação" encontra arrays que contêm esse elemento:

js
const encontrados = await livros
  .find(
    {
      "editora.cidade": "São Paulo",
      categorias: "programação",
    },
    {
      projection: {
        _id: 0,
        titulo: 1,
        "editora.nome": 1,
      },
    },
  )
  .sort({ titulo: 1 })
  .toArray();

console.log(encontrados);
[ { titulo: 'JavaScript do zero', editora: { nome: 'Código Aberto' } }, { titulo: 'Node.js na prática', editora: { nome: 'Código Aberto' } } ]

O filtro decide quem entra. A projeção decide o que sai. find() cria um cursor; sort() acrescenta ordenação; toArray() consome o cursor. Para um resultado potencialmente enorme, use limite, paginação por cursor ou iteração; não carregue tudo em memória sem medir.

Atualize sem substituir o documento inteiro

O preço e as categorias não devem sumir quando o estoque muda. Por isso usamos operadores de atualização. $inc soma 2 ao estoque e $set cria um campo interno sem substituir todo o objeto editora:

js
const alteracao = await livros.updateOne(
  { _id: "livro-1" },
  {
    $inc: { estoque: 2 },
    $set: { "editora.site": "codigoaberto.dev" },
  },
);

console.log({
  encontrados: alteracao.matchedCount,
  alterados: alteracao.modifiedCount,
});
{ encontrados: 1, alterados: 1 }

matchedCount responde se o filtro encontrou documento. modifiedCount responde se houve mudança. Eles podem ser diferentes: definir um campo com o valor que ele já possui encontra o documento, mas não altera seu estado.

Confira o pedaço afetado, em vez de confiar apenas na contagem:

js
const conferido = await livros.findOne(
  { _id: "livro-1" },
  { projection: { _id: 0, estoque: 1, editora: 1 } },
);

console.log(conferido);
{ estoque: 10, editora: { nome: 'Código Aberto', cidade: 'São Paulo', site: 'codigoaberto.dev' } }

Você verá mais filtros e operadores na próxima aula de CRUD MongoDB com Node.js.

Provoque a regra de estoque

Agora teste a porta fechada, não só o caminho que passa. A tentativa abaixo tem todos os campos obrigatórios, mas viola minimum: 0:

js
try {
  await livros.insertOne({
    titulo: "Livro inválido",
    preco: 20,
    estoque: -1,
  });
} catch (erro) {
  console.log({
    erro: "documento recusado",
    codigo: erro.code,
    motivo: "estoque abaixo de zero",
  });
}
{ erro: 'documento recusado', codigo: 121, motivo: 'estoque abaixo de zero' }

O código 121 é DocumentValidationFailure. Em uma API, registre os detalhes técnicos e transforme a falha em resposta útil. Não dependa da frase integral do servidor como contrato: versões e regras diferentes podem produzir detalhes distintos; o código e a validação que você definiu são as pistas estáveis.

Missão: acrescente um formato sem abandonar o contrato

Cadastre livro-4 como e-book. Ele deve manter titulo, preco e estoque, mas pode adicionar formatoArquivo: "epub" e tamanhoMB: 4.2. Depois faça uma consulta que devolva apenas título e formato:

js
await livros.insertOne({
  _id: "livro-4",
  titulo: "APIs sem mistério",
  preco: 34.9,
  estoque: 999,
  formatoArquivo: "epub",
  tamanhoMB: 4.2,
});

console.log(await livros.findOne(
  { formatoArquivo: "epub" },
  { projection: { _id: 0, titulo: 1, formatoArquivo: 1 } },
));

await client.close();
{ titulo: 'APIs sem mistério', formatoArquivo: 'epub' }

A missão termina quando o quarto documento entra, a projeção não traz preço nem estoque e uma tentativa com estoque: -1 continua falhando. Assim você prova as duas ideias ao mesmo tempo: a coleção aceita variação útil e preserva a regra que não pode variar. Quando a dúvida for onde incorporar ou separar dados, avance para modelagem MongoDB.

  • mongodb
  • documentos
  • colecoes
  • bson
  • node.js

Perguntas frequentes

Documento MongoDB é igual a objeto JavaScript?
Eles têm forma parecida, e o driver converte valores entre os dois. O MongoDB, porém, armazena BSON, que possui tipos próprios como ObjectId, Date e Decimal128.
Uma coleção obriga todos os documentos a ter os mesmos campos?
Não por padrão. Você pode guardar documentos com formatos diferentes e adicionar validação de schema para os campos e tipos que devem ser obrigatórios.
Para que serve o campo _id?
Ele identifica unicamente um documento dentro da coleção. MongoDB cria um índice único para _id e o driver gera ObjectId quando o campo é omitido.
Como consulto um campo dentro de outro documento?
Use notação de ponto no filtro, por exemplo editora.cidade. O mesmo formato aparece em projeções, atualizações e criação de índices.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em MongoDB 8.0.28, MongoDB Node.js Driver 7.5.0, Node 26.3.0 e Docker 29.5.3, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. MongoDB Manual — Introduction to MongoDB — mongodb.com
  2. MongoDB Manual — Documents — mongodb.com
  3. MongoDB Manual — Collections — mongodb.com
  4. MongoDB Manual — Schema Validation — mongodb.com

Continue por aqui