You need to enable JavaScript to run this app. 如何在ASP.NET Core中使用MongoDB驱动查询含上下限的日期范围数据
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP.NET Core中使用MongoDB驱动查询含上下限的日期范围数据

MongoDB 日期范围查询上限条目未命中问题

现有环境与数据

MongoDB 中 DomainObjects 集合的部分测试数据如下:

> db.DomainObjects.find()
// 省略其余条目
{ "_id" : ObjectId("6..3"), "lev" : 7, "date" : ISODate("2021-02-01T00:00:00Z"), "val" : 29.1 }
{ "_id" : ObjectId("6..4"), "lev" : 7, "date" : ISODate("2021-02-02T00:00:00Z"), "val" : 20.3 }
{ "_id" : ObjectId("6..5"), "lev" : 7, "date" : ISODate("2021-02-05T00:00:00Z"), "val" : 15.8 }
// 省略其余条目

ASP.NET Core 项目通过指定版本的官方 MongoDB 驱动连接数据库,集合初始化代码如下:

public DomainService(IDomainDatabaseSettings settings)
{
    var client = new MongoClient(settings.ConnectionString);
    var database = client.GetDatabase(settings.DatabaseName);
    _repo = database.GetCollection<Domain>(settings.DomainCollectionName);
}

原有实现逻辑

最初的服务层查询方法希望实现包含上下限的日期范围匹配:

public List<Domain> Get(int lev, DateTime dateFrom, DateTime dateTo) 
{
    Expression<Func<Domain, bool>> expr = entry => 
        (entry.lev == lev)                    
        && (entry.date.CompareTo(dateFrom) >= 0) 
        && (entry.date.CompareTo(dateTo) <= 0);
    return _repo.Find(expr).ToList();
}

通过GET接口调用的示例地址:

https://localhost:45645/api/DomainObjects/7/?dateFrom=2021-02-01&dateTo=2021-02-02

控制器层的完整代码:

[HttpGet("{lev:int}")]
public ActionResult<List<Domain>> Get(int lev, [FromQuery] DateTime? dateFrom = null, [FromQuery] DateTime? dateTo = null) 
{
    if (!dateFrom.HasValue) 
    {
        dateFrom = DateTime.MinValue;
        return _domainService.Get(lev, (DateTime) dateFrom, (DateTime) dateTo);
    }
    if (!dateTo.HasValue) 
    {
        dateTo = DateTime.Today;
        return _domainService.Get(lev, (DateTime) dateFrom, (DateTime) dateTo);
    }
    return _domainService.Get(lev, (DateTime) dateFrom, (DateTime) dateTo);
}

实际异常表现

执行上述请求时,仅能返回包含下限的起始条目,dateTo对应的上限条目没有被纳入结果集。

预期目标

  • 请求省略dateFrom下限值时,从集合存储的最早条目开始返回
  • 请求省略dateTo上限值时,返回从给定dateFrom开始、到当天(含当日全时间范围)的所有匹配条目

异常根因

  • 时区不匹配:MongoDB 存储的日期为 UTC 格式的ISODate类型,ASP.NET Core 从查询字符串解析得到的DateTime默认带本地时区属性,直接比对会产生固定偏移,导致上限值判定失效。
  • 表达式翻译兼容问题:MongoDB 官方 LINQ 驱动对CompareTo()方法的表达式翻译存在边界兼容缺陷,容易出现范围判定偏差。
  • 时间粒度缺失:传入的dateTo为纯日期格式时,默认解析结果为当日零点,会漏掉当日零点之后的所有数据。

修正方案

  1. 统一时区:所有查询用的DateTime统一转换为UTC格式,和数据库存储的时区基准保持一致。
  2. 替换查询表达式:移除CompareTo()调用,直接使用标准的日期比较运算符,保证 LINQ 表达式能被驱动正确翻译成 MongoDB 可识别的查询语句。
  3. 补全时间粒度:当dateTo只有日期值时,将其调整为当日最后一个毫秒级时间点,确保覆盖当天全时段的数据。
    修正后的服务层代码:
public List<Domain> Get(int lev, DateTime dateFrom, DateTime dateTo) 
{
    // 统一转换为UTC时区,和数据库存储基准对齐
    var utcDateFrom = dateFrom.ToUniversalTime();
    // 上限时间补全到当日最后一个毫秒点,覆盖全天数据
    var utcDateTo = DateTime.SpecifyKind(dateTo.Date, DateTimeKind.Utc)
        .AddDays(1)
        .AddMilliseconds(-1)
        .ToUniversalTime();

    Expression<Func<Domain, bool>> expr = entry => 
        entry.lev == lev                    
        && entry.date >= utcDateFrom
        && entry.date <= utcDateTo;

    return _repo.Find(expr).ToList();
}

简化后的控制器代码(移除冗余分支):

[HttpGet("{lev:int}")]
public ActionResult<List<Domain>> Get(int lev, [FromQuery] DateTime? dateFrom = null, [FromQuery] DateTime? dateTo = null) 
{
    // 未传下限默认取DateTime最小值,转UTC即可匹配最早存储的条目
    var finalDateFrom = dateFrom ?? DateTime.MinValue;
    // 未传上限默认取当天日期
    var finalDateTo = dateTo ?? DateTime.Today;

    return _domainService.Get(lev, finalDateFrom, finalDateTo);
}

修正后执行原测试请求,2021-02-01和2021-02-02对应的两个条目都会被正确返回,未传参数的分支也能符合预期查询范围要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 23:45:07