【问题标题】:Using JDBC with MongoDB to query Dates that are stored in String使用 JDBC 和 MongoDB 查询存储在 String 中的日期
【发布时间】:2020-12-08 11:14:29
【问题描述】:

因此,如标题所示,我的 MongoDB 数据库中有以下示例文档:

    {"_id":{"$oid":"5fcf541b466a3d10f55f8241"}, "dateOfBirth":"1992-11-02T12:05:17"}

如您所见,日期存储为字符串而不是 ISODate 对象。据我所知,MongoDB 应该仍然能够将其作为日期进行处理和查询。 (source)

因此,我尝试通过以下方式在我的 java 应用程序中使用 JDBC 查询它:

    java.util.Date queryDate = new GregorianCalendar(1980, Calendar.JANUARY, 1).getTime();
    Bson query = Filters.gte("dateOfBirth", queryDate);
    FindIterable<Document> result = collection.find(query);

但是,这不起作用。我的想法是,如果我传入一个 java.util.Date,那么 Filters.gte() 方法就会知道我的意思是查询一个日期,它会在 MongoDB 中按预期工作。但是,我得到 0 个匹配项。

我还尝试在我的 queryDate 上放置一个格式化程序(之前用于不同的目的):

    DateFormat dformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    Bson query = Filters.gte("dateOfBirth", dformat.format(queryDate));

但是,这导致 Filters.gte() 将其作为字符串查询,根据 String-Comparison,因此大致按字母顺序。这让我最初认为原来的 java.util.Date 版本确实/应该知道,我查询的是日期而不是字符串,它只是以某种方式未能将数据库中的日期类型转换为日期类型?我不确定它应该如何工作。

我知道这是一个小众案例用法,我确实应该在 mongoDB 中插入日期作为 ISODate,但是在我现在的特殊情况下,这不是一个选项。

如果我使用 JDBC,有没有办法在 MongoDB 中查询存储为字符串的日期?

【问题讨论】:

    标签: java mongodb


    【解决方案1】:

    次要观点:您正在为 MongoDB 使用 Java 连接器。 JDBC 驱动程序适用于使用 SQL 查询语言的关系数据库。因此,我在您的问题中将JDBC 标签更改为Java

    将日期作为字符串处理

    关于文档中的日期时间格式:由于您使用的格式以及它存储为字符串,因此可以在运行查询时使用字符串比较。词法排序将确保您的字符串比较等同于日期时间比较。这就是您链接到的问题中的代码所使用的内容。

    如果您有任何以其他字符串格式存储的数据(例如“dd-MM-yyyy”),其中字符串排序与日期时间排序不匹配,那么显然这个假设就会失效。

    无论你如何继续,你应该 avoid the old and problematic Java DateCalendar 类。相反,使用现代的java.time 类。 More background here.

    在您的情况下,您的文档存储的日期时间数据没有任何时区或偏移信息。您可以为此使用java.time.LocalDateTime。此名称中的“本地”一词实际上意味着“没有特定的地区或时区” - 这与您在 Mongo 文档中的内容相匹配。

    Java 导入:

    import java.time.LocalDateTime;
    import java.time.Month;
    import java.time.format.DateTimeFormatter;
    

    还有一个本地日期时间示例:

    LocalDateTime ldt = LocalDateTime.of(1980, Month.JANUARY, 1, 0, 0);
    DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
    String s = ldt.format(dtf); // "1980-01-01T00:00:00"
    

    将日期作为对象使用

    如果您想在查询中直接使用 Java LocalDate 对象,而不是使用字符串比较,您可以使用投影在查询结果中创建日期对象,然后直接使用 Java LocalDate 对象在您的过滤器中:

    Bson resultsWithDate = Aggregates.project(Projections.fields(
            Projections.include("dateOfBirth"),
            Projections.computed("birthDate", Projections.computed("$toDate", "$dateOfBirth"))
    ));
    

    上述投影向每个检索到的文档添加一个新的dateOfBirth 字段,并通过$toDate 运算符填充它。

    然后我们可以应用我们的过滤器:

    collection.aggregate(
            Arrays.asList(
                    resultsWithDate,
                    Aggregates.match(Filters.gte("birthDate", ldt)))
    ).forEach(printConsumer);
    

    过滤器现在使用我们的ldt 对象,来自上方。

    我正在使用以下辅助方法在控制台中将每个结果文档打印为 JSON 字符串:

    Consumer<Document> printConsumer = (final Document document) -> {
        System.out.println(document.toJson());
    };
    

    可能有一种更紧凑或更有效的方式来构建这个 MongoDB 聚合 - 我不是 Mongo 的普通用户。

    另外,作为最后一点:我使用 Mongo $toDate 运算符没有指定时区 - 所以它默认为祖鲁时间(UT 时区),如下面的示例输出所示:

    {
        "_id": {
            "$oid": "5fcf541b466a3d10f55f8241"
        },
        "dateOfBirth": "1992-11-02T12:05:17",
        "birthDate": {
            "$date": "1992-11-02T12:05:17Z"
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-11-11
      • 1970-01-01
      • 1970-01-01
      • 2012-03-18
      • 2014-10-24
      • 2014-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多