• 在 MongoDB 的 CRUD 操作中使用日期


    1. 概述

    在本教程中,我们将使用 MongoDB Java Driver 来执行与日期相关的 CRUD 操作,例如创建和更新带有日期字段的文档,以及查询, 更新和删除日期字段在给定范围内的文档。

    2. 设置

    在深入实施之前,让我们设置我们的工作环境。

    2.1. Maven 依赖

    首先,您应该安装了 MongoDB。 如果您不这样做,您可以按照官方 MongoDB 安装 指南 进行操作。

    接下来,让我们将 MongoDB Java 驱动程序 作为依赖项添加到我们的 pom.xml 文件中:

    <dependency>
        <groupId>org.mongodbgroupId>
        <artifactId>mongodb-driver-syncartifactId>
        <version>4.6.0version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.2. POJO 数据模型

    让我们定义一个 POJO 来表示我们数据库中包含的文档:

    public class Event {
        private String title;
        private String location;
        private LocalDateTime dateTime;
    
        public Event() {}
        public Event(String title, String location, LocalDateTime dateTime) {
            this.title = title;
            this.location = location;
            this.dateTime = dateTime;
        }
        
        // standard setters and getters
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    请注意,我们已经声明了两个构造函数。 MongoDB 使用无参数构造函数默认。 在本教程中,另一个构造函数供我们自己使用。

    我们还要注意,虽然 dateTime 可能是 String 变量,但最佳实践是对日期字段使用特定于日期/时间的 JDK 类。 使用 String 字段来表示日期需要额外的努力来确保值的格式正确。

    我们现在准备将客户端连接到我们的数据库。

    2.3. MongoDB 客户端

    为了让 MongoDB 序列化/反序列化我们的 Event POJO,我们需要向 MongoDB 的 CodecRegistry 注册 PojoCodecProvider

    CodecProvider codecProvider = PojoCodecProvider.builder().automatic(true).build();
    CodecRegistry codecRegistry = fromRegistries(getDefaultCodecRegistry(), fromProviders(codecProvider));
    
    • 1
    • 2

    让我们创建一个将使用我们注册的 PojoCodecProvider 的数据库、集合和客户端:

    MongoClient mongoClient = MongoClients.create(uri);
    MongoDatabase db = mongoClient.getDatabase("calendar").withCodecRegistry(codecRegistry);
    MongoCollection<Event> collection = db.getCollection("my_events", Event.class);
    
    • 1
    • 2
    • 3

    我们现在已准备好创建文档并执行与日期相关的 CRUD 操作。

    3. 创建带有日期字段的文档

    在我们的 POJO 中,我们使用 LocalDateTime 而不是 String,以便更轻松地处理日期值。 现在让我们利用 LocalDateTime 的便捷 API 构造 Event 对象来利用它:

    Event pianoLessonsEvent = new Event("Piano lessons", "Foo Blvd",
      LocalDateTime.of(2022, 6, 4, 11, 0, 0));
    Event soccerGameEvent = new Event("Soccer game", "Bar Avenue",
      LocalDateTime.of(2022, 6, 10, 17, 0, 0));
    
    • 1
    • 2
    • 3
    • 4

    我们可以将新的 Events 插入到我们的数据库中,如下所示:

    InsertOneResult pianoLessonsInsertResult = collection.insertOne(pianoLessonsEvent);
    InsertOneResult soccerGameInsertResult = collection.insertOne(soccerGameEvent);
    
    • 1
    • 2

    让我们通过检查插入文档的 id 来验证插入是否成功:

    assertNotNull(pianoLessonsInsertResult.getInsertedId());
    assertNotNull(soccerGameInsertResult.getInsertedId());
    
    • 1
    • 2

    4. 查询符合日期条件的文档

    现在我们的数据库中有 Events,让我们根据它们的日期字段检索它们。

    我们可以使用相等过滤器 (eq) 来检索与特定日期和时间匹配的文档:

    LocalDateTime dateTime = LocalDateTime.of(2022, 6, 10, 17, 0, 0);
    Event event = collection.find(Filters.eq("dateTime", dateTime)).first();
    
    • 1
    • 2

    让我们检查生成的 Event 的各个字段:

    assertEquals("Soccer game", event.title);
    assertEquals("Bar Avenue", event.location);
    assertEquals(dateTime, event.dateTime);
    
    • 1
    • 2
    • 3

    我们还可以使用 MongoDB BasicDBObject 类以及 gtelte 运算符来使用日期范围构建更复杂的查询:

    LocalDateTime from = LocalDateTime.of(2022, 06, 04, 12, 0, 0);
    LocalDateTime to = LocalDateTime.of(2022, 06, 10, 17, 0, 0);
    
    BasicDBObject object = new BasicDBObject();
    object.put("dateTime", BasicDBObjectBuilder.start("$gte", from).add("$lte", to).get());
    
    List<Event> events = collection.find(object, Event.class).into(new ArrayList<Event>());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    由于足球比赛是我们查询的日期范围内唯一的 Event,我们应该在 list 中只看到一个 Event 对象,不包括钢琴课:

    assertEquals(1, events.size());
    assertEquals("Soccer game", events.get(0).title);
    assertEquals("Bar Avenue", events.get(0).location);
    assertEquals(dateTime, events.get(0).dateTime);
    
    • 1
    • 2
    • 3
    • 4

    5. 更新文档

    让我们探索两个基于日期字段更新文档的用例。 首先,我们将更新单个文档的日期字段,然后我们将更新与日期范围匹配的多个文档。

    5.1. 更新文档的日期字段

    要更新 MongoDB 文档,我们可以使用 updateOne() 方法。 让我们也使用 currentDate() 方法来设置钢琴课事件的 dateTime 字段:

    Document document = new Document().append("title", "Piano lessons");
    
    Bson update = Updates.currentDate("dateTime");
    UpdateOptions options = new UpdateOptions().upsert(false);
    
    UpdateResult result = collection.updateOne(document, update, options);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    请注意,updateOne() 的第一个参数是一个 Document 对象,MongoDB 将使用它来匹配我们数据库中的单个条目。 如果多个文档匹配,MongoDB 将只更新它遇到的第一个文档。 我们还要注意我们将 false 传递给 upsert() 方法。 如果我们改为传入 true,如果现有文档都不匹配,MongoDB 将插入一个新文档。

    我们可以通过检查修改了多少文档来确认操作是否成功:

    assertEquals(1, result.getModifiedCount());
    
    • 1

    5.2. 更新符合日期条件的文档

    为了更新多个文档,MongoDB 提供了 updateMany 方法。 在此示例中,我们将更新与查询中的日期范围匹配的多个events 。

    updateOne() 不同,updateMany() 方法需要第二个 Bson 对象来封装查询条件,该条件将定义我们要更新的文档。 在这种情况下,我们将通过引入 lt 字段运算符来指定涵盖 2022 年所有事件的日期范围:

    LocalDate updateManyFrom = LocalDate.of(2022, 1, 1);
    LocalDate updateManyTo = LocalDate.of(2023, 1, 1);
    
    Bson query = Filters.and(Filters.gte("dateTime", updateManyFrom), Filters.lt("dateTime", updateManyTo));
    Bson updates = Updates.currentDate("dateTime");
    
    UpdateResult result = collection.updateMany(query, updates);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    就像 updateOne() 一样,我们可以通过检查 result 对象的更新计数来确认此操作更新了多个events:

    assertEquals(2, result.getModifiedCount());
    
    • 1

    6. 删除符合日期条件的文档

    与更新一样,我们可以一次从数据库中删除一个或多个文档。 假设我们需要删除 2022 年的所有event。让我们使用 Bson 日期范围查询和 deleteMany() 方法来做到这一点:

    LocalDate deleteFrom = LocalDate.of(2022, 1, 1);
    LocalDate deleteTo = LocalDate.of(2023, 1, 1);
    
    Bson query = Filters.and(Filters.gte("dateTime", deleteFrom), Filters.lt("dateTime", deleteTo));
    DeleteResult result = collection.deleteMany(query);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    由于我们在本教程中创建的所有事件都有一个 2022 dateTime 字段值,deleteMany() 将它们全部从我们的集合中删除。 我们可以通过检查删除计数来确认这一点:

    assertEquals(2, result.getDeletedCount());
    
    • 1

    7. 使用 时区(Time Zones)

    MongoDB 以 UTC 存储日期,并且无法更改。 因此,如果我们希望我们的日期字段特定于一个时区,我们可以将时区偏移存储在一个单独的字段中并自己进行转换。 让我们将该字段添加为 String

    public String timeZoneOffset;
    
    • 1

    我们需要调整构造函数,以便在创建events时设置新字段:

    public Event(String title, String location, LocalDateTime dateTime, String timeZoneOffset) {
        this.title = title;
        this.location = location;
        this.dateTime = dateTime;
        this.timeZoneOffset = timeZoneOffset;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    我们现在可以创建特定时区的events并将其插入到我们的数据库中。 让我们使用 ZoneOffset 类来避免手动格式化时区偏移 String

    LocalDateTime utcDateTime = LocalDateTime.of(2022, 6, 20, 11, 0, 0);
    
    Event pianoLessonsTZ = new Event("Piano lessons", "Baz Bvld", utcDateTime, ZoneOffset.ofHours(2).toString());
    InsertOneResult pianoLessonsTZInsertResult = collection.insertOne(pianoLessonsTZ);
    
    assertNotNull(pianoLessonsTZInsertResult.getInsertedId());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    请注意,由于偏移量是相对于 UTC 的,所以 dateTime 成员变量必须表示 UTC 时间,以便我们以后可以正确转换它。 从集合中检索文档后,我们可以使用偏移字段和 OffsetDateTime 类进行转换:

    OffsetDateTime dateTimeWithOffset = OffsetDateTime.of(pianoLessonsTZ.dateTime, ZoneOffset.of(pianoLessonsTZ.timeZoneOffset));
    
    • 1

    8. 结尾

    在本文中,我们学习了如何使用 Java 和 MongoDB 数据库执行与日期相关的 CRUD 操作。

    我们使用日期值来创建、检索、更新或删除数据库中的文档。 在我们的示例中,我们介绍了各种帮助程序类并介绍了在处理日期时很有帮助的 MongoDB 运算符。 最后,为了解决 MongoDB 如何仅以 UTC 存储日期的问题,我们学习了如何处理需要特定时区的日期/时间值。

  • 相关阅读:
    RabbitMQ_概述
    Pointnet++的改进
    ​开发者上架ios系统iphone苹果xcode签名的封装应用ipa文件用于四个分类怎么选择打包方式?
    Python "爬虫"出发前的装备之一正则表达式
    LeetCode:1155. 掷骰子等于目标和的方法数(C++)
    2.deep copy与 shallow copy 区别
    Python 教程之如何在 Python 中处理大型数据集CSV、Pickle、Parquet、Feather 和 HDF5 的比较
    【C语言】文件相关操作
    涨粉超100万,这些博主的内容密码是什么?
    你的下一个压测工具可以是nGrinder
  • 原文地址:https://blog.csdn.net/wjw465150/article/details/127776688