介绍
在本实验中,你将学习如何在 MongoDB 中处理日期。你将练习插入带有日期值的文档、查询特定日期范围内的文档、格式化日期字段以供显示、更新现有日期字段以及按日期对集合进行排序。本实验提供了关于 MongoDB 日期相关功能的全面实践指南,这些功能对于管理时间序列数据、调度和日志记录应用程序至关重要。
插入带日期值的文档
在第一步中,你将连接到 MongoDB 服务器并插入几个包含日期值的文档。这将为你将在后续步骤中执行的查询和操作奠定基础。
首先,通过在终端中运行 mongosh 命令来打开 MongoDB shell。这将把你连接到正在运行的 MongoDB 实例。
mongosh
进入 shell 后,你将看到一个类似 test> 的提示符。让我们切换到一个名为 datelab 的新数据库。如果数据库不存在,MongoDB 会在你首次插入数据时为你创建它。
use datelab
现在,你将向一个名为 events 的新集合中插入三个文档。每个文档将代表一个事件并包含一个日期。MongoDB 将日期存储为 BSON Date 对象,你可以使用 new Date() 构造函数来创建它们。
逐个插入以下文档。第一个文档使用 ISO-8601 日期字符串,第二个文档使用当前日期和时间,第三个文档使用毫秒级的 Unix 时间戳。
db.events.insertOne({
event_name: "Conference",
date: new Date("2024-06-15T10:30:00Z")
})
db.events.insertOne({
event_name: "System Maintenance",
timestamp: new Date()
})
db.events.insertOne({
event_name: "Project Deadline",
timestamp: new Date(1718476800000)
})
插入文档后,你可以使用 find() 方法来验证它们是否已正确添加,该方法会检索集合中的所有文档。
db.events.find()
你的输出应该与此类似,尽管 _id 值和“System Maintenance”的 timestamp 对你来说会不同。
[
{
_id: ObjectId("65d38f8a1c2d3e4f5a6b7c8d"),
event_name: 'Conference',
date: ISODate('2024-06-15T10:30:00.000Z')
},
{
_id: ObjectId("65d38f9c1c2d3e4f5a6b7c8e"),
event_name: 'System Maintenance',
timestamp: ISODate('2024-02-19T14:55:24.123Z')
},
{
_id: ObjectId("65d38fb11c2d3e4f5a6b7c8f"),
event_name: 'Project Deadline',
timestamp: ISODate('2024-06-15T18:00:00.000Z')
}
]
你现在已经成功插入了带日期值的文档。在下一步中,你将学习如何根据日期查询这些文档。
按日期范围查询文档
在你的集合中有数据后,你现在可以执行查询来查找落在特定日期范围内的文档。这对于处理计划事件、日志或时间敏感数据的应用程序来说是一个常见的需求。
首先,让我们向集合中添加更多事件,使查询更有趣。我们将使用 insertMany() 方法一次添加三个文档。
db.events.insertMany([
{
event_name: "Summer Conference",
date: new Date("2024-07-15T09:00:00Z")
},
{
event_name: "Winter Workshop",
date: new Date("2024-01-20T14:30:00Z")
},
{
event_name: "Spring Meetup",
date: new Date("2024-04-10T11:15:00Z")
}
])
现在你总共有六个事件。让我们查找所有发生在 2024 年 6 月 1 日之后的事件。为此,你将使用“大于”运算符 $gt。
db.events.find({
date: { $gt: new Date("2024-06-01") }
})
接下来,让我们查找发生在 2024 年上半年,具体来说是 1 月 1 日到 6 月 1 日之间的所有事件。你可以为此结合使用“大于等于”($gte) 和“小于”($lt) 运算符。
db.events.find({
date: {
$gte: new Date("2024-01-01"),
$lt: new Date("2024-06-01")
}
})
查询将返回“Winter Workshop”和“Spring Meetup”事件。输出应如下所示:
[
{
_id: ObjectId("65d392a11c2d3e4f5a6b7c91"),
event_name: 'Winter Workshop',
date: ISODate('2024-01-20T14:30:00.000Z')
},
{
_id: ObjectId("65d392a11c2d3e4f5a6b7c92"),
event_name: 'Spring Meetup',
date: ISODate('2024-04-10T11:15:00.000Z')
}
]
这些示例演示了如何使用比较运算符($gt、$gte、$lt、$lte)根据日期字段有效地过滤文档。
使用聚合格式化日期输出
通常,你需要将日期显示为特定的、人类可读的格式。MongoDB 的聚合框架为此提供了强大的工具。在本步骤中,你将使用 $dateToString 运算符来格式化你的日期字段。
聚合框架通过一系列阶段处理文档。我们将使用一个 $project 阶段来重塑我们的文档并创建一个新的、格式化的日期字段。
让我们将事件的 date 字段格式化为 YYYY-MM-DD 格式。此查询将仅处理包含 date 字段的文档。
db.events.aggregate([
{
$project: {
event_name: 1,
formatted_date: {
$dateToString: {
format: "%Y-%m-%d",
date: "$date"
}
}
}
}
])
让我们分解一下这个命令:
db.events.aggregate([...]): 在events集合上启动一个聚合管道。$project: 一个重塑文档的阶段。我们包含event_name并创建一个新字段formatted_date。$dateToString: 一个将日期对象转换为字符串的运算符。format: "%Y-%m-%d": 指定输出格式。%Y是年份,%m是月份,%d是日期。date: "$date": 指定原始文档中的输入日期字段。$前缀表示字段路径。
输出将显示原始事件名称和新格式化的日期字符串。请注意,没有 date 字段的文档(如“System Maintenance”)将从结果中省略。
[
{ _id: ObjectId("..."), event_name: 'Conference', formatted_date: '2024-06-15' },
{ _id: ObjectId("..."), event_name: 'Summer Conference', formatted_date: '2024-07-15' },
{ _id: ObjectId("..."), event_name: 'Winter Workshop', formatted_date: '2024-01-20' },
{ _id: ObjectId("..."), event_name: 'Spring Meetup', formatted_date: '2024-04-10' }
]
你还可以使用 $year 和 $month 等运算符提取日期的各个组成部分,例如年份或月份。
db.events.aggregate([
{
$project: {
event_name: 1,
year: { $year: "$date" },
month: { $month: "$date" },
day: { $dayOfMonth: "$date" }
}
}
])
这使你能够精细地控制处理和呈现日期信息的方式。
更新日期字段
你的数据并非一成不变。你可能需要更新日期字段,例如重新安排事件或添加修改时间戳。在本步骤中,你将学习如何使用各种更新运算符来更新日期字段。
首先,让我们将“Conference”事件重新安排到一个新日期。我们将使用 updateOne() 方法来定位单个文档,并使用 $set 运算符来更改其 date 字段。
db.events.updateOne(
{ event_name: "Conference" },
{
$set: {
date: new Date("2024-09-01T10:00:00Z"),
status: "Rescheduled"
}
}
)
现在,让我们执行批量更新。我们将把所有发生在 2024 年 5 月 1 日之前的事件标记为“Archived”。我们还将添加一个新字段 last_modified 来记录这次更新发生的时间。updateMany() 方法将修改所有匹配的文档,而 $currentDate 运算符非常适合将字段设置为当前服务器时间。
db.events.updateMany(
{ date: { $lt: new Date("2024-05-01") } },
{
$set: { status: "Archived" },
$currentDate: { last_modified: true }
}
)
让我们通过检索所有文档来验证更改。.pretty() 方法已被弃用,因此我们将只使用 find()。
db.events.find()
你将看到“Conference”具有新的日期和状态。“Winter Workshop”和“Spring Meetup”现在被标记为“Archived”并具有 last_modified 时间戳。
已存档事件的示例输出:
{
"_id" : ObjectId("..."),
"event_name" : "Winter Workshop",
"date" : ISODate("2024-01-20T14:30:00Z"),
"status" : "Archived",
"last_modified" : ISODate("2024-02-19T15:10:00Z")
}
这些操作展示了你如何精确地修改文档中与日期相关的信息。
按日期对文档进行排序
你将学习的最后一个基本操作是排序。按时间顺序显示事件是一个常见的需求。MongoDB 可以轻松地按任何字段(包括日期)对查询结果进行排序。
要对文档进行排序,请将 .sort() 方法附加到 find() 查询。sort() 方法接受一个文档,该文档指定要排序的字段和排序顺序。值为 1 表示升序(从最早到最晚),值为 -1 表示降序(从最晚到最早)。
让我们按 date 字段的升序检索所有事件。
db.events.find().sort({ date: 1 })
这将按时间顺序(从“Winter Workshop”最早到“Summer Conference”最晚)列出事件。不包含 date 字段的文档(如果包含在查询中)将首先排序。
现在,让我们按降序对事件进行排序,以便首先查看最近的事件。
db.events.find().sort({ date: -1 })
你还可以将排序与过滤结合起来。例如,让我们查找所有未归档的事件,并按日期对它们进行排序。
db.events.find({ status: { $ne: "Archived" } }).sort({ date: 1 })
输出将按时间顺序显示非归档事件。
[
{
_id: ObjectId("..."),
event_name: 'System Maintenance',
timestamp: ISODate("...")
},
{
_id: ObjectId("..."),
event_name: 'Project Deadline',
timestamp: ISODate('2024-06-15T18:00:00.000Z')
},
{
_id: ObjectId("..."),
event_name: 'Summer Conference',
date: ISODate('2024-07-15T09:00:00.000Z')
},
{
_id: ObjectId("..."),
event_name: 'Conference',
date: ISODate('2024-09-01T10:00:00.000Z'),
status: 'Rescheduled'
}
]
排序是按时间顺序有意义地呈现数据的重要工具。完成后,你可以通过键入 exit 或按 Ctrl+D 来退出 MongoDB shell。
总结
在本实验中,你学习了在 MongoDB 中处理日期的基本技术。你首先使用不同的格式插入带有日期值的文档。然后,你练习了使用比较运算符根据日期范围查询文档。之后,你探索了聚合框架,用于格式化日期字段以提高可读性。你还学会了如何更新日期字段和添加修改时间戳。最后,你掌握了按日期对集合进行排序,以按时间顺序呈现数据。这些技能对于任何在 MongoDB 中处理基于时间数据的开发者来说都至关重要。

