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

Golang中MongoDB时间范围查询返回全部子文档问题排查

解决MongoDB查询返回整个数组而非匹配子项的问题

当前查询的filter仅用于判断整个员工文档是否存在符合时间条件的排班记录,一旦匹配成功,MongoDB会返回整个员工文档(包含所有schedules子文档),而非仅筛选符合时间范围的子项。这就是查询5月时返回所有排班(因存在符合条件的子项,整个文档被返回)、查询8月时无匹配文档返回空的原因。

方案1:使用聚合管道筛选所有匹配的排班子文档

聚合管道可精确筛选数组中符合条件的所有子文档,是最可靠的方案:

layout := "2006-01-02T15:04:05.999999"
startTime, err := time.Parse(layout, scheduleRequest.StartDate)
if err != nil {
    log.Fatal(err)
}
endTime, err := time.Parse(layout, scheduleRequest.EndDate)
if err != nil {
    log.Fatal(err)
}

mongoStartTime := primitive.NewDateTimeFromTime(startTime)
mongoEndTime := primitive.NewDateTimeFromTime(endTime)

pipeline := []bson.M{
    // 匹配目标员工,且存在符合条件的排班
    {
        "$match": bson.M{
            "_id": scheduleRequest.EmployeeID,
            "schedules.end_time": bson.M{"$gte": mongoStartTime, "$lte": mongoEndTime},
        },
    },
    // 筛选schedules数组中符合时间条件的子文档
    {
        "$project": bson.M{
            "first_name": 1,
            "last_name":  1,
            // 按需保留其他字段
            "schedules": bson.M{
                "$filter": bson.M{
                    "input": "$schedules",
                    "as":    "schedule",
                    "cond": bson.M{
                        "$and": []bson.M{
                            {"$gte": []interface{}{"$$schedule.end_time", mongoStartTime}},
                            {"$lte": []interface{}{"$$schedule.end_time", mongoEndTime}},
                        },
                    },
                },
            },
        },
    },
}

ctx := context.TODO()
cursor, err := employeeCollection.Aggregate(ctx, pipeline)
if err != nil {
    log.Fatal(err)
}
defer cursor.Close(ctx)

var results []bson.M
if err := cursor.All(ctx, &results); err != nil {
    log.Fatal(err)
}
// results中的文档仅包含符合时间范围的schedules子项

方案2:使用投影$elemMatch(仅返回第一个匹配项)

若只需返回数组中第一个符合条件的子文档,可采用此简化方式,但无法返回多个匹配项:

layout := "2006-01-02T15:04:05.999999"
startTime, err := time.Parse(layout, scheduleRequest.StartDate)
endTime, err := time.Parse(layout, scheduleRequest.EndDate)

mongoStartTime := primitive.NewDateTimeFromTime(startTime)
mongoEndTime := primitive.NewDateTimeFromTime(endTime)

filter := bson.M{
    "_id": scheduleRequest.EmployeeID,
    "schedules.end_time": bson.M{"$gte": mongoStartTime, "$lte": mongoEndTime},
}

// 投影仅返回匹配的第一个schedules子文档
projection := bson.M{
    "schedules": bson.M{"$elemMatch": bson.M{"end_time": bson.M{"$gte": mongoStartTime, "$lte": mongoEndTime}}},
    "first_name": 1,
    "last_name":  1,
}

ctx := context.TODO()
cursor, err := employeeCollection.Find(ctx, filter, options.Find().SetProjection(projection))
if err != nil {
    log.Fatal(err)
}
defer cursor.Close(ctx)

var results []bson.M
if err := cursor.All(ctx, &results); err != nil {
    log.Fatal(err)
}

补充说明

  • 若你的时间范围逻辑是「排班与查询月份有重叠」(而非仅end_time在范围内),需调整$filter的cond条件为:
    "$and": []bson.M{
            {"$lte": []interface{}{"$$schedule.start_time", mongoEndTime}},
            {"$gte": []interface{}{"$$schedule.end_time", mongoStartTime}},
        },
    }
    
  • 处理时间解析时务必检查错误,避免因解析失败导致的逻辑异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 05:53:14