Vincular Documentos MongoDB

MongoDBBeginner
Pratique Agora

Introdução

Neste laboratório, você aprenderá os fundamentos do estabelecimento de relacionamentos entre documentos no MongoDB. Essa técnica, conhecida como referenciamento (referencing), é essencial para construir estruturas de banco de dados complexas e organizadas. Você praticará a criação de coleções, a inserção de documentos com referências a outros documentos, a recuperação e combinação de dados relacionados usando o estágio de agregação $lookup, e o gerenciamento do ciclo de vida desses documentos vinculados. Ao final deste laboratório, você terá uma compreensão sólida de como modelar e gerenciar relacionamentos um-para-muitos (one-to-many) em seu banco de dados MongoDB.

Estabelecendo Relacionamentos de Documentos

Nesta primeira etapa, você criará duas coleções separadas e estabelecerá um relacionamento entre elas. Modelaremos um cenário comum: um banco de dados de biblioteca com authors (autores) e books (livros). Cada livro referenciará seu autor.

Primeiro, abra o MongoDB Shell. Esta interface interativa de linha de comando permite que você interaja com sua instância do MongoDB.

mongosh

Uma vez dentro do shell, você verá um prompt test>. Vamos mudar para um novo banco de dados chamado library_database. Se o banco de dados não existir, o MongoDB o criará para você quando você armazenar dados pela primeira vez.

use library_database

Agora, vamos criar a coleção authors inserindo dois documentos. Cada documento tem um _id único do tipo ObjectId, que usaremos para referenciamento.

db.authors.insertMany([
  {
    _id: ObjectId("660a1f5c9b8f8b1234567890"),
    name: "Jane Austen",
    nationality: "British"
  },
  {
    _id: ObjectId("660a1f5c9b8f8b1234567891"),
    name: "George Orwell",
    nationality: "British"
  }
]);

Você deverá ver uma confirmação de que os documentos foram inseridos com sucesso.

Exemplo de saída:

{
  "acknowledged": true,
  "insertedIds": {
    "0": ObjectId("660a1f5c9b8f8b1234567890"),
    "1": ObjectId("660a1f5c9b8f8b1234567891")
  }
}

Em seguida, crie a coleção books. Em cada documento de livro, o campo author_id armazenará o ObjectId do autor correspondente da coleção authors. Isso cria o vínculo entre um livro e seu autor.

db.books.insertMany([
  {
    title: "Pride and Prejudice",
    author_id: ObjectId("660a1f5c9b8f8b1234567890"),
    year: 1813
  },
  {
    title: "1984",
    author_id: ObjectId("660a1f5c9b8f8b1234567891"),
    year: 1949
  }
]);

Exemplo de saída:

{
  "acknowledged": true,
  "insertedIds": {
    "0": ObjectId("660b2a1c9b8f8b1234567892"),
    "1": ObjectId("660b2a1c9b8f8b1234567893")
  }
}

Você agora criou com sucesso duas coleções e vinculou documentos na coleção books a documentos na coleção authors. Mantenha o MongoDB shell aberto para a próxima etapa.

Consultando Documentos Vinculados

Agora que você estabeleceu relacionamentos, o próximo passo lógico é recuperar os dados vinculados em uma única consulta. O framework de agregação do MongoDB fornece o estágio $lookup para esse propósito, que executa um join externo esquerdo (left outer join) para outra coleção.

Certifique-se de que você ainda está no shell mongosh e usando o library_database.

Vamos realizar uma consulta para buscar todos os livros e incorporar as informações de seus autores correspondentes nos resultados.

db.books.aggregate([
  {
    $lookup: {
      from: "authors",
      localField: "author_id",
      foreignField: "_id",
      as: "author_details"
    }
  }
]);

O estágio $lookup une a coleção books com a coleção authors. Vamos revisar seus parâmetros:

  • from: "authors": Especifica a coleção com a qual fazer o join.
  • localField: "author_id": Especifica o campo dos documentos de entrada (da coleção books).
  • foreignField: "_id": Especifica o campo dos documentos na coleção "from" (a coleção authors).
  • as: "author_details": Especifica o nome do novo campo de array a ser adicionado à saída. Este array conterá os documentos de autor correspondentes.

Exemplo de saída para um dos documentos:

[
  {
    "_id": ObjectId("..."),
    "title": "Pride and Prejudice",
    "author_id": ObjectId("660a1f5c9b8f8b1234567890"),
    "year": 1813,
    "author_details": [
      {
        "_id": ObjectId("660a1f5c9b8f8b1234567890"),
        "name": "Jane Austen",
        "nationality": "British"
      }
    ]
  },
  ...
]

Como você pode ver, o campo author_details é um array contendo o documento completo do autor. Este recurso poderoso permite que você recupere dados abrangentes sem a necessidade de realizar várias consultas a partir de sua aplicação.

Atualizando Documentos Relacionados

Dados em um banco de dados raramente são estáticos. Nesta etapa, você aprenderá como atualizar documentos nas coleções authors e books. Como estamos usando referências, você pode atualizar as informações de um autor em um local, e todas as consultas que se unem a esse autor refletirão automaticamente a mudança.

Vamos adicionar um ano de nascimento ao documento de Jane Austen. Usaremos o método updateOne com o operador $set para adicionar um novo campo sem sobrescrever o documento inteiro.

db.authors.updateOne(
  { name: "Jane Austen" },
  {
    $set: {
      birth_year: 1775
    }
  }
);

Exemplo de saída:

{
  "acknowledged": true,
  "insertedId": null,
  "matchedCount": 1,
  "modifiedCount": 1,
  "upsertedCount": 0
}

Agora, vamos atualizar os detalhes de um livro. Adicionaremos um genre a "Pride and Prejudice".

db.books.updateOne(
  { title: "Pride and Prejudice" },
  {
    $set: {
      genre: "Romance"
    }
  }
);

Para verificar se ambas as atualizações foram bem-sucedidas, você pode consultar os documentos diretamente.

Primeiro, verifique o autor:

db.authors.findOne({ name: "Jane Austen" });

Em seguida, verifique o livro:

db.books.findOne({ title: "Pride and Prejudice" });

Você verá os novos campos birth_year e genre nos respectivos documentos. A referência author_id no documento do livro permanece inalterada, preservando o vínculo.

A parte final do gerenciamento de relacionamentos é lidar com exclusões. Ao remover um documento, você deve considerar o que acontece com os documentos que o referenciam. O MongoDB não impõe integridade referencial automaticamente, portanto, esta é uma tarefa que você deve gerenciar no nível da aplicação.

Primeiro, vamos excluir um livro mantendo seu autor. Removeremos o livro "1984".

db.books.deleteOne({ title: "1984" });

Exemplo de saída:

{ "acknowledged": true, "deletedCount": 1 }

Se você agora consultar a coleção books, verá que apenas um livro permanece. O documento "George Orwell" na coleção authors não é afetado.

Agora, considere um cenário mais complexo: remover um autor e todos os seus livros associados. Isso requer um processo de várias etapas para manter a integridade dos dados.

Primeiro, encontre o ID do autor e armazene-o em uma variável. Removeremos "Jane Austen".

const authorId = db.authors.findOne({ name: "Jane Austen" })._id;

Em seguida, use este ID para excluir todos os livros associados a esse autor. O comando deleteMany é usado caso um autor tenha vários livros.

db.books.deleteMany({ author_id: authorId });

Finalmente, remova o próprio documento do autor.

db.authors.deleteOne({ _id: authorId });

Este processo manual e de várias etapas garante que você não deixe documentos de livros "órfãos" com referências author_id inválidas. Você pode verificar que tanto o livro "Pride and Prejudice" quanto o autor "Jane Austen" foram removidos de suas respectivas coleções.

Agora você pode sair do shell do MongoDB.

exit

Resumo

Neste laboratório, você aprendeu as técnicas essenciais para trabalhar com documentos vinculados no MongoDB. Você começou criando as coleções authors e books e estabelecendo um relacionamento de um para muitos usando referências de documentos. Em seguida, praticou como recuperar e combinar dados dessas coleções relacionadas usando o estágio de agregação $lookup. Além disso, você aprendeu como atualizar documentos individuais sem quebrar seus links e, finalmente, como gerenciar corretamente as exclusões para manter a integridade dos dados, removendo documentos relacionados em um processo controlado e multifásico. Essas habilidades formam uma base sólida para projetar e construir aplicações de banco de dados NoSQL mais sofisticadas e interconectadas.