You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS DocumentDB与Java:日期范围查询无结果问题排查

问题

首次接触MongoDB,用Java查询AWS DocumentDB集合时,能正常获取全量数据总数,但按日期范围过滤的查询始终返回0条结果。尝试了多种过滤写法(包括BasicDBObject和Document构建条件),传入起始日期、结束日期或两者组合均无效。

观察到DataGrid显示的日期格式为2023-10-01,而非带时间戳的2023-10-01 05:00:00,怀疑是日期格式/类型不匹配导致的问题。

以下是相关代码:

package com.example.mongodb.service;

import com.mongodb.BasicDBObject;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import jakarta.annotation.PostConstruct;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * Do Things with DocumentDB.
 */
public class DocDBService {
    private String collectionName = "myCollection";

    private MongoClient mongoClient;
    private MongoDatabase database;

    private String username;
    private String password;
    private String server;
    private String dbName;

    /**
     * Construct with our username, password, and server.
     */
    public DocDBService(String usernameIn, String passwordIn, String serverIn, String dbNameIn) {
        username = usernameIn;
        password = passwordIn;
        server = serverIn;
        dbName = dbNameIn;

        String template = "mongodb://%s:%s@%s";
        String connectionString = String.format(template, username, password, server);
        mongoClient = MongoClients.create(connectionString);
        database = mongoClient.getDatabase(dbName);
    }

    /** This is working. */
    public long getLength() {
        BasicDBObject obj;

        return database.getCollection(collectionName).countDocuments();
    }

    /* I've tried a few things. None are working. */
    public long getLength(Date earliest, Date latest) {
        /*
        BasicDBObject query = new BasicDBObject();
        if (earliest != null) {
            query.put("date", new BasicDBObject("$gt", earliest));
        }
        if (latest != null) {
            query.put("date", new BasicDBObject("$lt", latest));
        }

        System.out.println(query.toJson());

        MongoCursor<?> cursor = database.getCollection(collectionName).find(query).iterator();
        long rv = 0;
        while (cursor.hasNext()) {
            ++rv;
            cursor.next();
        }
         */
        long rv = 0;
        Document filter = new Document();
        if (earliest != null) {
            filter.append("$gte", earliest);
        }
        if (latest != null) {
            filter.append("$lte", latest);
        }
        System.out.println(filter.toJson());
        rv = database.getCollection(collectionName).countDocuments(new Document("date", filter));
        return rv;
    }
}

当传入两个日期时,打印的过滤条件为:

{"$gte": {"$date": "2023-10-01T05:00:00Z"}, "$lte": {"$date": "2023-11-02T05:00:00Z"}}

核心原因&修复方案

1. 先确认字段实际类型

DataGrid显示的2023-10-01大概率是格式化后的结果,要先明确集合里date字段的真实类型:是BSON Date类型,还是字符串类型?

可以加一段代码验证:

// 取一条样本数据查看date字段类型
Document sample = database.getCollection(collectionName).find().first();
if (sample != null) {
    Object dateVal = sample.get("date");
    System.out.println("date字段类型:" + dateVal.getClass().getName());
    System.out.println("date字段原始值:" + dateVal);
}

2. 针对不同类型的修复

情况A:字段是字符串类型(如"2023-10-01")

如果字段存的是字符串,用Java的Date对象查询会因为类型不匹配返回空结果。需要把查询的日期转为和存储格式一致的字符串(YYYY-MM-DD)再做范围匹配:

import java.text.SimpleDateFormat;

public long getLength(Date earliest, Date latest) {
    SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
    Document dateFilter = new Document();

    if (earliest != null) {
        dateFilter.append("$gte", dateFormatter.format(earliest));
    }
    if (latest != null) {
        dateFilter.append("$lte", dateFormatter.format(latest));
    }

    // 无过滤条件时返回全量
    if (dateFilter.isEmpty()) {
        return getLength();
    }

    return database.getCollection(collectionName).countDocuments(new Document("date", dateFilter));
}

情况B:字段是BSON Date类型

如果字段是Date类型,之前的代码逻辑没问题,但旧代码里的BasicDBObject写法有条件覆盖问题:两次query.put("date", ...)会把前一个条件覆盖,导致最终只有一个范围条件。现在用Document的写法是对的,但可以优化一下空判断:

public long getLength(Date earliest, Date latest) {
    Document dateFilter = new Document();

    if (earliest != null) {
        dateFilter.append("$gte", earliest);
    }
    if (latest != null) {
        dateFilter.append("$lte", latest);
    }

    if (dateFilter.isEmpty()) {
        return getLength();
    }

    return database.getCollection(collectionName).countDocuments(new Document("date", dateFilter));
}

内容的提问来源于stack exchange,提问作者Joseph Larson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 07:15:10