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

MongoDB如何按月/日时间范围查询未来1个月内的用户生日

问题描述

我需要对存储了Date类型生日字段的用户数据库进行查询,筛选出即将过生日的用户。示例用户存储数据如下:

  • name: "John Doe"
  • birthday: 1980-06-30T00:00:00.000+00:00
    需求为检索未来1个月内过生日的用户。

此前在pymongo中编写的查询逻辑存在缺陷,仅能返回生日恰好为当天、以及恰好为1个月后当天的用户,无法匹配区间内所有符合条件的结果,原有错误代码如下:

find({
    "$and": [
        {"$and": [
            {"$expr": {"$gte": [{"$month": "$birthday"}, today.month]}},
            {"$expr": {"$gte": [{"$dayOfMonth": "$birthday"}, today.day]}}
        ]},
        {"$and": [
            {"$expr": {"$lte": [{"$month": "$birthday"}, one_month_from_today.month]}},
            {"$expr": {"$lte": [{"$dayOfMonth": "$birthday"}, one_month_from_today.day]}}
        ]}
    ]
})
错误原因

原有逻辑将月份和日期拆分为独立条件做大小比较,完全没有处理跨月、跨年的边界场景:

  • 跨月场景:例如今天是6月20日,7月5日过生日的用户,月份7大于6满足第一个判断条件,但日期5小于20,会被原逻辑的日期大于等于判断直接过滤
  • 跨年场景:例如今天是12月20日,1个月后是次年1月20日,原逻辑要求生日月份既要大于等于12又要小于等于1,逻辑本身矛盾,完全匹配不到1月过生日的用户
正确实现方案

核心思路是将用户生日统一换算为距离当前最近一次生日的日期,再和「今日0点」「30天后0点」两个基准时间做区间比较,同时兼容闰日、跨月、跨年的特殊情况。

实现逻辑

  • 先计算两个基准时间:当日0点时间、30天后0点时间
  • 提取用户生日的月、日字段,拼接为当前年份的对应日期,做闰日兼容(如果用户生日是2月29日且当前年为平年,自动按2月28日计算,避免日期转换报错)
  • 如果拼接出的当前年生日早于当日,说明今年的生日已经过了,将生日日期加1年取明年的生日
  • 判断换算后的最近一次生日是否落在两个基准时间的区间内即可

pymongo可直接使用的代码

from datetime import datetime, timedelta

# 计算时间基准
today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
end_date = today + timedelta(days=30)
current_year = today.year

db.user.find({
    "$expr": {
        "$let": {
            "vars": {
                "birth_month": {"$month": "$birthday"},
                "birth_day": {"$dayOfMonth": "$birthday"},
                # 生成当前年对应的生日,自动兼容2月29日闰日场景
                "current_year_birth": {
                    "$dateFromParts": {
                        "year": current_year,
                        "month": "$$birth_month",
                        "day": {
                            "$min": [
                                "$$birth_day",
                                # 取出生日月的最后一天,避免平年2月29日转换报错
                                {"$dayOfMonth": {"$dateFromParts": {"year": current_year, "month": "$$birth_month", "day": 1}}}
                            ]
                        }
                    }
                }
            },
            "in": {
                "$and": [
                    # 生日大于等于今日
                    {"$gte": [
                        {"$cond": [
                            {"$gte": ["$$current_year_birth", today]},
                            "$$current_year_birth",
                            # 今年生日已过则取明年的生日
                            {"$dateAdd": {"startDate": "$$current_year_birth", "unit": "year", "amount": 1}}
                        ]},
                        today
                    ]},
                    # 生日早于30天后的日期
                    {"$lt": [
                        {"$cond": [
                            {"$gte": ["$$current_year_birth", today]},
                            "$$current_year_birth",
                            {"$dateAdd": {"startDate": "$$current_year_birth", "unit": "year", "amount": 1}}
                        ]},
                        end_date
                    ]}
                ]
            }
        }
    }
})

注意:如果使用的MongoDB版本低于5.0,不支持$dateAdd操作符,可以用$dateFromParts手动给年份加1替换对应逻辑即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 02:39:16