链接 MongoDB 文档

MongoDBBeginner
立即练习

介绍

在本实验中,你将学习在 MongoDB 中建立文档之间关系的基础知识。这种被称为引用的技术对于构建复杂且有组织的数据库结构至关重要。你将练习创建集合、插入包含对其他文档引用的文档、使用 $lookup 聚合阶段检索和组合相关数据,以及管理这些链接文档的生命周期。完成本实验后,你将对如何在 MongoDB 数据库中建模和管理一对多关系有扎实的理解。

这是一个实验(Guided Lab),提供逐步指导来帮助你学习和实践。请仔细按照说明完成每个步骤,获得实际操作经验。根据历史数据,这是一个 初级 级别的实验,完成率为 100%。获得了学习者 100% 的好评率。

建立文档关系

在第一步中,你将创建两个独立的集合,并在它们之间建立关系。我们将模拟一个常见的场景:一个包含 authorsbooks 的图书馆数据库。每本书都将引用其作者。

首先,打开 MongoDB Shell。这是一个交互式的命令行界面,允许你与 MongoDB 实例进行交互。

mongosh

进入 shell 后,你将看到一个 test> 提示符。让我们切换到一个名为 library_database 的新数据库。如果数据库不存在,MongoDB 会在你首次存储数据时为你创建它。

use library_database

现在,通过插入两个文档来创建 authors 集合。每个文档都有一个唯一的 ObjectId 类型的 _id,我们将用它来进行引用。

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

你应该会看到文档已成功插入的确认信息。

示例输出:

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

接下来,创建 books 集合。在每个 book 文档中,author_id 字段将存储来自 authors 集合的相应作者的 ObjectId。这就在 book 和其作者之间建立了链接。

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

示例输出:

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

你现在已经成功创建了两个集合,并在 books 集合中的文档与 authors 集合中的文档之间建立了链接。请保持 MongoDB shell 打开以进行下一步。

查询链接文档

既然你已经建立了关系,下一步就是在一个查询中检索链接的数据。MongoDB 的聚合框架为此提供了 $lookup 阶段,它执行一个左外连接到另一个集合。

确保你仍然在 mongosh shell 中并使用 library_database

让我们执行一个查询来获取所有书籍,并将它们对应的作者信息嵌入到结果中。

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

$lookup 阶段将 books 集合与 authors 集合连接起来。让我们回顾一下它的参数:

  • from: "authors": 指定要连接的集合。
  • localField: "author_id": 指定输入文档(来自 books 集合)中的字段。
  • foreignField: "_id": 指定 "from" 集合(authors 集合)中文档的字段。
  • as: "author_details": 指定要添加到输出的新数组字段的名称。这个数组将包含匹配的作者文档。

其中一个文档的示例输出:

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

正如你所见,author_details 字段是一个数组,其中包含作者的完整文档。这个强大的功能允许你检索全面的数据,而无需从你的应用程序执行多个查询。

更新相关文档

数据库中的数据很少是静态的。在这一步中,你将学习如何更新 authorsbooks 集合中的文档。因为我们使用了引用,你可以在一个地方更新作者的信息,所有与该作者进行连接的查询都会自动反映出这个变化。

让我们为 Jane Austen 的文档添加一个出生年份。我们将使用 updateOne 方法和 $set 操作符来添加一个新字段,而不会覆盖整个文档。

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

示例输出:

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

现在,让我们更新一本书的详细信息。我们将为 "Pride and Prejudice" 添加一个 genre

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

为了验证两个更新是否成功,你可以直接查询这些文档。

首先,检查作者:

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

然后,检查书籍:

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

你将在相应的文档中看到新的 birth_yeargenre 字段。书籍文档中的引用 author_id 保持不变,保留了链接。

管理和移除文档链接

管理关系的最后一部分是处理删除。当你移除一个文档时,你必须考虑引用它的文档会发生什么。MongoDB 不会自动强制执行引用完整性,所以这是你必须在应用程序层面管理的任务。

首先,让我们删除一本图书,同时保留其作者。我们将移除图书 "1984"。

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

示例输出:

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

如果你现在查询 books 集合,你会发现只剩下一本书了。"George Orwell" 在 authors 集合中的文档不受影响。

现在,考虑一个更复杂的场景:移除一个作者及其所有相关的图书。这需要一个多步骤的过程来维护数据完整性。

首先,找到作者的 ID 并将其存储在一个变量中。我们将移除 "Jane Austen"。

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

接下来,使用这个 ID 删除与该作者相关的所有图书。如果一个作者有多本书,则使用 deleteMany 命令。

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

最后,移除作者文档本身。

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

这个手动、多步骤的过程确保你不会留下带有无效 author_id 引用的“孤儿”图书文档。你可以验证图书 "Pride and Prejudice" 和作者 "Jane Austen" 都已从它们各自的集合中移除。

现在你可以退出 MongoDB shell。

exit

总结

在本实验中,你学习了在 MongoDB 中处理链接文档的基本技术。你首先创建了 authorsbooks 集合,并使用文档引用建立了“一对多”关系。然后,你练习了如何使用 $lookup 聚合阶段从这些相关集合中检索和组合数据。此外,你还学习了如何在不破坏链接的情况下更新单个文档,最后,如何通过一个受控的多步骤过程移除相关文档来正确管理删除操作,以维护数据完整性。这些技能为你设计和构建更复杂、更互联的 NoSQL 数据库应用程序奠定了坚实的基础。