介绍
在本实验中,你将学习如何有效地管理 MongoDB 中的嵌入式文档。嵌入式文档,也称为嵌套文档,是 MongoDB 数据模型的核心特性,它允许你在单个文档中存储复杂、分层的数据。你将学习一系列技术,包括创建包含嵌套数据的文档、更新其中的特定字段、移除元素以及查询这些复杂结构。你还将学习如何使用模式验证(schema validation)来强制执行一致的数据结构。这些技能对于使用 MongoDB 构建健壮高效的应用程序至关重要。
在本实验中,你将学习如何有效地管理 MongoDB 中的嵌入式文档。嵌入式文档,也称为嵌套文档,是 MongoDB 数据模型的核心特性,它允许你在单个文档中存储复杂、分层的数据。你将学习一系列技术,包括创建包含嵌套数据的文档、更新其中的特定字段、移除元素以及查询这些复杂结构。你还将学习如何使用模式验证(schema validation)来强制执行一致的数据结构。这些技能对于使用 MongoDB 构建健壮高效的应用程序至关重要。
在本步骤中,你将学习如何在 MongoDB 中创建具有嵌套结构的文档。这是在单个文档中建模相关数据的基本技能。
首先,打开 MongoDB Shell (mongosh) 以开始与数据库进行交互。本实验中后续的所有命令都将在该 shell 中运行,除非另有说明。
mongosh
接下来,切换到一个名为 bookstore 的新数据库。如果此数据库不存在,MongoDB 会在你首次向其中存储数据时为你创建它。
use bookstore
现在,你将创建一个名为 books 的集合并插入一个文档。此文档将包含嵌套对象和嵌套对象数组,代表一本书的详细信息。
db.books.insertOne({
title: "Advanced MongoDB",
author: {
name: "Jane Smith",
contact: {
email: "jane.smith@example.com",
phone: "+1-555-123-4567"
}
},
published: {
year: 2023,
publisher: "Tech Publications"
},
chapters: [
{ number: 1, title: "Introduction to Nested Documents" },
{ number: 2, title: "Advanced Document Structures" }
]
})
在你刚刚创建的文档中:
author 和 published 是嵌套文档(对象)。author 文档包含另一个嵌套文档 contact。chapters 是一个数组,其中包含多个嵌套文档,每个文档代表一个章节。要查看文档并确认其结构,请使用 find() 方法。
db.books.find()
你应该会看到以下输出,确认文档已正确插入。_id 是 MongoDB 自动生成的唯一标识符。
[
{
_id: ObjectId("..."),
title: 'Advanced MongoDB',
author: {
name: 'Jane Smith',
contact: {
email: 'jane.smith@example.com',
phone: '+1-555-123-4567'
}
},
published: {
year: 2023,
publisher: 'Tech Publications'
},
chapters: [
{ number: 1, title: 'Introduction to Nested Documents' },
{ number: 2, title: 'Advanced Document Structures' }
]
}
]
创建文档后,你通常需要修改其中的部分内容。在本步骤中,你将学习如何更新嵌套文档和数组中的特定字段。你应该仍然处于上一步的 mongosh shell 中。
首先,让我们更新作者的联系信息。为此,你将使用 $set 操作符配合点表示法(dot notation)来指定要更改字段的确切路径。此命令将更改电话号码并添加一个新的 website 字段。
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $set: {
"author.contact.phone": "+1-888-999-0000",
"author.contact.website": "www.janesmith.com"
} }
)
点表示法 "author.contact.phone" 告诉 MongoDB 进入 author 对象,然后进入 contact 对象,并更新 phone 字段。
接下来,你将使用 $push 操作符向 chapters 数组添加一个新章节。
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $push: {
chapters: {
number: 3,
title: "MongoDB Advanced Techniques"
}
} }
)
你也可以更新数组中的特定元素。让我们修改第一个章节的标题。我们使用位置操作符 $,它充当匹配查询条件("chapters.number": 1)的第一个数组元素的占位符。
db.books.updateOne(
{ title: "Advanced MongoDB", "chapters.number": 1 },
{ $set: {
"chapters.$.title": "Introduction to Nested Documents (Revised)"
} }
)
为了验证所有更改,请再次检索文档。.pretty() 方法会格式化输出,使其更易于阅读。
db.books.find({ title: "Advanced MongoDB" }).pretty()
输出将显示更新后的电话号码、新的网站、添加的第三章以及修改后的第一章标题。
在本步骤中,你将学习如何删除文档的某些部分。这包括删除特定字段、整个嵌套文档以及数组中的元素。
首先,让我们使用 $unset 操作符从作者的联系信息中删除 website 字段。提供给 $unset 的值(在此例中为空字符串 "")无关紧要;该操作符仅删除指定的字段。
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $unset: { "author.contact.website": "" } }
)
接下来,你将从数组中删除一个元素。让我们使用 $pull 操作符从 chapters 数组中删除第三个章节(即 number: 3 的那个)。$pull 操作符会删除所有匹配指定条件的数组元素。
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $pull: {
chapters: { number: 3 }
} }
)
最后,你可以删除整个嵌套对象。让我们再次使用 $unset 操作符从 author 文档中删除 contact 对象。
db.books.updateOne(
{ title: "Advanced MongoDB" },
{ $unset: { "author.contact": "" } }
)
要查看这些删除操作的结果,请再次查询文档。
db.books.find({ title: "Advanced MongoDB" }).pretty()
输出将显示 website 字段和整个 contact 对象已消失,并且 chapters 数组现在只包含两个元素。
查询是数据库的基本操作。在本步骤中,你将学习如何根据嵌套对象和数组中的值来查询文档。为了确保我们有一组干净的数据用于这些示例,请先删除现有的 books 集合。
db.books.drop()
现在,插入几个具有不同嵌套结构的新文档以练习查询。
db.books.insertMany([
{
title: "MongoDB Essentials",
author: {
name: "John Doe",
experience: { years: 5, specialization: "Database Design" }
},
tags: ["beginner", "database", "nosql"],
chapters: [
{ number: 1, title: "Introduction", pages: 25 },
{ number: 2, title: "Advanced Concepts", pages: 45 }
]
},
{
title: "Advanced Database Techniques",
author: {
name: "Jane Smith",
experience: { years: 8, specialization: "Distributed Systems" }
},
tags: ["advanced", "distributed", "nosql"],
chapters: [
{ number: 1, title: "System Design", pages: 35 },
{ number: 2, title: "Performance Optimization", pages: 55 }
]
}
])
要按嵌套文档中的字段查找书籍,请使用点表示法(dot notation)。此查询查找由 "John Doe" 撰写的书籍。
db.books.find({ "author.name": "John Doe" })
你可以深入到更深的嵌套结构。此查询查找作者专业领域为 "Database Design" 的书籍。
db.books.find({ "author.experience.specialization": "Database Design" })
要查找数组包含特定值的文档,你可以直接查询数组字段。这会查找所有标记为 "nosql" 的书籍。
db.books.find({ tags: "nosql" })
你还可以查询数组元素满足特定条件的文档。此查询查找至少有一个章节页数超过 40 页的书籍,使用了 $gt(大于)操作符。
db.books.find({ "chapters.pages": { $gt: 40 } })
最后,你可以组合多个条件。此查询查找标记为 "advanced" 且作者拥有 5 年或以上经验($gte 表示大于或等于)的书籍。
db.books.find({
"author.experience.years": { $gte: 5 },
tags: "advanced"
})
为了保持数据一致性,MongoDB 允许你使用 JSON Schema validation 来强制执行集合中文档的特定结构。在本步骤中,你将创建一个名为 courses 的新集合,并为其设置一个 validator,以确保所有文档都符合预定义的结构。
首先,创建一个名为 courses 的新集合。在创建时,你将传递一个包含 schema 规则的 validator 选项。
db.createCollection("courses", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["title", "instructor", "duration", "topics"],
properties: {
title: {
bsonType: "string",
description: "must be a string and is required"
},
instructor: {
bsonType: "object",
required: ["name", "email"],
properties: {
name: { bsonType: "string" },
email: {
bsonType: "string",
pattern: "^.+@.+$"
}
}
},
duration: {
bsonType: "int",
minimum: 1,
maximum: 100
},
topics: {
bsonType: "array",
minItems: 1,
items: { bsonType: "string" }
}
}
}
}
})
此 schema 要求每个文档都包含 title、instructor、duration 和 topics。它还定义了每个字段的数据类型,包括 instructor 对象和 topics 数组的嵌套规则。
现在,尝试插入一个符合这些规则的文档。此操作应该会成功。
db.courses.insertOne({
title: "MongoDB Advanced Techniques",
instructor: {
name: "Jane Smith",
email: "jane.smith@example.com"
},
duration: 40,
topics: ["Nested Documents", "Schema Validation"]
})
接下来,尝试插入一个违反 schema 规则的文档。此文档的 instructor.name 数据类型不正确,电子邮件格式无效,duration 超出了允许的范围,并且 topics 数组为空。
db.courses.insertOne({
title: "Invalid Course",
instructor: {
name: 123,
email: "invalid-email"
},
duration: 200,
topics: []
})
此插入将失败,MongoDB 将返回 Document failed validation 错误。这可以防止不一致的数据被保存,并有助于维护数据库的完整性。
在本实验中,你学习了管理 MongoDB 中嵌入式文档的基本技术。你首先创建了具有复杂嵌套结构(包括对象和数组)的文档。然后,你练习了使用点表示法(dot notation)和 $set、$push 等操作符来更新特定字段。你还学会了如何使用 $unset 和 $pull 来删除数据。此外,你还探索了如何对嵌套数据执行定向查询,并最终通过为集合定义和应用 JSON Schema validator 来强制执行数据完整性。这些技能对于构建能够有效利用 MongoDB 灵活文档模型的应用程序至关重要。