介绍
在本实验中,你将学习如何处理 MongoDB 数组。数组是 MongoDB 中的一种基本数据结构,它允许你在单个文档中存储值的列表。你将探索各种操作,包括创建带有数组字段的文档、添加和移除元素、更新数组中的值以及基于数组内容执行查询。这些技能对于在 MongoDB 中有效管理复杂数据结构至关重要。
通过本实验的学习,你将对如何使用 MongoDB 数组获得扎实、实用的理解,从而能够构建更复杂、更灵活的数据库模式。
在本实验中,你将学习如何处理 MongoDB 数组。数组是 MongoDB 中的一种基本数据结构,它允许你在单个文档中存储值的列表。你将探索各种操作,包括创建带有数组字段的文档、添加和移除元素、更新数组中的值以及基于数组内容执行查询。这些技能对于在 MongoDB 中有效管理复杂数据结构至关重要。
通过本实验的学习,你将对如何使用 MongoDB 数组获得扎实、实用的理解,从而能够构建更复杂、更灵活的数据库模式。
在第一步中,你将连接到 MongoDB 服务器并创建一个包含数组字段的新文档。数组之所以强大,是因为它们允许你直接在文档中存储多个相关值,例如标签、评论或课程。
首先,打开 MongoDB shell 开始与你的数据库进行交互。在本实验中,你将在 mongosh shell 中执行所有后续操作。
mongosh
进入 shell 后,你将看到类似 test> 的提示符。让我们切换到为本实验预先配置的 arraylab 数据库。
use arraylab
setup 脚本已经创建了一个 students 集合并插入了一个文档。现在,你将为一位名叫“Alice Johnson”的学生插入一个新文档。此文档将包含一个 courses 字段,它是一个字符串数组。
db.students.insertOne({
name: "Alice Johnson",
age: 22,
courses: ["Mathematics", "Computer Science", "Physics"]
})
此命令将单个文档插入到 students 集合中。courses 字段包含一个包含三个字符串元素的数组。
为了确认文档已成功创建,你可以使用 find() 方法检索集合中的所有文档。.pretty() 方法会格式化输出,使其更易于阅读。
db.students.find().pretty()
你应该会看到两个文档:一个是设置过程中创建的“Bob Smith”的文档,另一个是你刚刚添加的“Alice Johnson”的文档。
[
{
_id: ObjectId("..."),
name: 'Bob Smith',
grades: [ 95, 87, 92 ],
activities: [ 'Chess Club', 'Debate Team' ]
},
{
_id: ObjectId("..."),
name: 'Alice Johnson',
age: 22,
courses: [ 'Mathematics', 'Computer Science', 'Physics' ]
}
]
创建数组后,一项常见任务是向其添加新元素。在这一步中,你将学习如何使用 $push 操作符将元素追加到现有数组中。
要向数组添加单个元素,请在更新操作中使用 $push 操作符。让我们为 Alice Johnson 的课程列表添加一门新课程,“Data Science”。
db.students.updateOne(
{ name: "Alice Johnson" },
{ $push: { courses: "Data Science" } }
)
在此命令中,第一个参数 { name: "Alice Johnson" } 是用于查找要更新的文档的过滤器。第二个参数 { $push: { courses: "Data Science" } } 指定了更新操作。$push 将值“Data Science”追加到 courses 数组。
让我们通过再次查找 Alice 的文档来验证更改。
db.students.find({ name: "Alice Johnson" }).pretty()
输出显示了已添加到数组的新课程。
[
{
_id: ObjectId("..."),
name: 'Alice Johnson',
age: 22,
courses: [ 'Mathematics', 'Computer Science', 'Physics', 'Data Science' ]
}
]
要一次添加多个元素,你可以将 $push 与 $each 修饰符结合使用。让我们为 Bob Smith 添加两项新活动。
db.students.updateOne(
{ name: "Bob Smith" },
{ $push: { activities: { $each: ["Robotics Club", "Swimming Team"] } } }
)
在这里,$each 告诉 $push 将提供的列表(["Robotics Club", "Swimming Team"])中的每个项目追加到 activities 数组。
也请验证此更新:
db.students.find({ name: "Bob Smith" }).pretty()
输出确认已添加两个新活动。
[
{
_id: ObjectId("..."),
name: 'Bob Smith',
grades: [ 95, 87, 92 ],
activities: [ 'Chess Club', 'Debate Team', 'Robotics Club', 'Swimming Team' ]
}
]
就像你可以添加元素一样,你也需要能够移除它们。MongoDB 为此目的提供了多种操作符。在这一步中,你将学习使用 $pull 按值移除元素,以及使用 $pop 按位置移除元素。
要根据值从数组中移除特定元素,请使用 $pull 操作符。让我们从 Alice 的课程列表中移除“Physics”。
db.students.updateOne(
{ name: "Alice Johnson" },
{ $pull: { courses: "Physics" } }
)
此命令会查找 Alice 的文档,并从她的 courses 数组中移除所有出现的“Physics”。检查结果:
db.students.find({ name: "Alice Johnson" }).pretty()
输出显示“Physics”已不再数组中。
[
{
_id: ObjectId("..."),
name: 'Alice Johnson',
age: 22,
courses: [ 'Mathematics', 'Computer Science', 'Data Science' ]
}
]
要一次性移除列表中匹配值的多个元素,你可以使用 $pullAll 操作符。让我们从 Bob 的活动中移除“Chess Club”和“Debate Team”。
db.students.updateOne(
{ name: "Bob Smith" },
{ $pullAll: { activities: ["Chess Club", "Debate Team"] } }
)
验证 Bob 文档的更新:
db.students.find({ name: "Bob Smith" }).pretty()
输出确认已移除指定的活动。
[
{
_id: ObjectId("..."),
name: 'Bob Smith',
grades: [ 95, 87, 92 ],
activities: [ 'Robotics Club', 'Swimming Team' ]
}
]
如果你需要从数组的开头或结尾移除元素,可以使用 $pop 操作符。使用 1 移除最后一个元素,使用 -1 移除第一个元素。让我们从 Alice 的列表中移除最后一门课程。
db.students.updateOne(
{ name: "Alice Johnson" },
{ $pop: { courses: 1 } }
)
让我们看看 Alice 课程的最终状态:
db.students.find({ name: "Alice Johnson" }).pretty()
输出显示最后一项元素,“Data Science”,已被移除。
[
{
_id: ObjectId("..."),
name: 'Alice Johnson',
age: 22,
courses: [ 'Mathematics', 'Computer Science' ]
}
]
更新数组中的现有元素是另一项关键操作。本步骤将介绍如何使用位置操作符更新数组元素。
要更新数组中的单个特定元素,你必须首先匹配文档和要更改的元素。然后,你可以使用位置操作符 $ 来执行更新。让我们将 Alice 的 courses 数组中的“Mathematics”更改为“Advanced Mathematics”。
db.students.updateOne(
{ name: "Alice Johnson", courses: "Mathematics" },
{ $set: { "courses.$": "Advanced Mathematics" } }
)
在此命令中,过滤器 { name: "Alice Johnson", courses: "Mathematics" } 会查找文档并识别数组中“Mathematics”第一次出现的位置。更新 { $set: { "courses.$": "Advanced Mathematics" } } 使用 courses.$ 来引用该匹配元素的位置并设置其新值。
验证更改:
db.students.find({ name: "Alice Johnson" }).pretty()
输出显示了更新后的课程名称。
[
{
_id: ObjectId("..."),
name: 'Alice Johnson',
age: 22,
courses: [ 'Advanced Mathematics', 'Computer Science' ]
}
]
要更新数组中匹配条件的所有元素,你可以使用 all-positional 操作符 $[ ]。让我们使用 $inc(递增)操作符将 Bob 的所有成绩提高 5 分。
db.students.updateOne(
{ name: "Bob Smith" },
{ $inc: { "grades.$[]": 5 } }
)
在这里,grades.$[] 将 $inc 操作应用于 grades 数组中的每个元素。
查看 Bob 的新成绩:
db.students.find({ name: "Bob Smith" }).pretty()
输出显示每项成绩都增加了 5 分。
[
{
_id: ObjectId("..."),
name: 'Bob Smith',
grades: [ 100, 92, 97 ],
activities: [ 'Robotics Club', 'Swimming Team' ]
}
]
查询是任何数据库的核心。MongoDB 提供了一套丰富的操作符,用于根据数组内容查询文档。在最后这一步中,你将学习如何通过匹配数组元素及其属性来查找文档。
要查找数组中包含特定元素的文档,你可以在查询过滤器中包含该值。让我们查找所有注册了“Computer Science”的学生。
db.students.find({ courses: "Computer Science" }).pretty()
此查询将返回 Alice 的文档,因为她的 courses 数组包含“Computer Science”。
要查找数组中包含指定元素集合中 所有 元素的文档,请使用 $all 操作符。
db.students.find({
courses: { $all: ["Advanced Mathematics", "Computer Science"] }
}).pretty()
此查询也将返回 Alice 的文档,因为她的 courses 数组同时包含这两个值。
对于数组元素的更复杂条件,$elemMatch 操作符非常有用。它允许你指定单个数组元素必须满足的多个条件。让我们查找至少有一门成绩大于 95 的学生。
db.students.find({
grades: { $elemMatch: { $gt: 95 } }
}).pretty()
此查询将返回 Bob 的文档,因为他现在有成绩超过了 95 分。$gt 代表“大于”(greater than)。
你还可以使用 $size 操作符根据数组中的元素数量进行查询。让我们查找恰好参加了两个活动的学生。
db.students.find({
activities: { $size: 2 }
}).pretty()
这将返回 Bob 的文档,因为他的 activities 数组当前有两个元素。
最后,让我们再添加一名学生来练习一个组合查询。
db.students.insertOne({
name: "Charlie Brown",
courses: ["Art", "Music", "Literature"],
grades: [88, 92, 85],
activities: ["Painting Club"]
})
现在,查找那些参加了“Art”或“Music”(使用 $in 操作符)并且至少有一门成绩大于或等于 90 分(使用 $elemMatch 和 $gte)的学生。
db.students.find({
courses: { $in: ["Art", "Music"] },
grades: { $elemMatch: { $gte: 90 } }
}).pretty()
此查询将返回“Charlie Brown”的文档,因为他满足这两个条件。
在本实验中,你学习了在 MongoDB 中处理数组的基本技术。你首先创建了包含数组字段的文档,然后练习了使用 $push 和 $each 添加元素。你探索了使用 $pull 和 $pullAll 按值移除元素,以及使用 $pop 按位置移除元素。你还学习了如何使用位置操作符 $ 更新特定数组元素,以及使用 $[ ] 操作符更新所有元素。最后,你练习了使用 $all、$elemMatch、$size 和 $in 等操作符根据数组内容查询文档。这些技能对于使用 MongoDB 中复杂、嵌套的数据结构构建和管理应用程序至关重要。