处理 MongoDB 日期

MongoDBBeginner
立即练习

介绍

在本实验中,你将学习如何在 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 中处理基于时间数据的开发者来说都至关重要。