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

如何用Mongoose查询Profile模型中生日月日在指定区间的记录?

Mongoose查询忽略年份匹配月日区间的解决方案

原代码问题分析

  • 两次赋值search.birthDate会互相覆盖,最终只有最后一个条件生效(比如同时传起始和结束日期时,只会保留$lte条件)
  • 未处理跨年度区间场景(例如查询11-01至次年02-01的生日)
  • 直接替换年份后比较日期,无法正确匹配不同出生年份的月日区间

解决方案思路

利用MongoDB的$expr查询运算符,结合$month和$dayOfMonth聚合函数,直接提取birthDate的月、日进行比较,完全忽略年份。同时需要区分普通区间(起始月日≤结束月日)和跨年度区间(起始月日>结束月日)两种场景。

具体实现代码

const dayjs = require('dayjs');

// 示例输入参数,可替换为实际传入值
const birthDateStart = '2023-01-01';
const birthDateEnd = '2023-06-01';

let birthdayQuery = {};

if (birthDateStart && birthDateEnd) {
  // 转成MongoDB兼容的1-12月份(dayjs月份是0-11)
  const startMonth = dayjs(birthDateStart).month() + 1;
  const startDay = dayjs(birthDateStart).date();
  const endMonth = dayjs(birthDateEnd).month() + 1;
  const endDay = dayjs(birthDateEnd).date();

  if (startMonth < endMonth || (startMonth === endMonth && startDay <= endDay)) {
    // 普通区间:不跨年,匹配月日在[start, end]之间
    birthdayQuery.$expr = {
      $and: [
        { $gte: [{ $month: '$birthDate' }, startMonth] },
        { $lte: [{ $month: '$birthDate' }, endMonth] },
        // 当月等于起始月时,日期需≥起始日
        { $or: [{ $ne: [{ $month: '$birthDate' }, startMonth] }, { $gte: [{ $dayOfMonth: '$birthDate' }, startDay] }] },
        // 当月等于结束月时,日期需≤结束日
        { $or: [{ $ne: [{ $month: '$birthDate' }, endMonth] }, { $lte: [{ $dayOfMonth: '$birthDate' }, endDay] }] }
      ]
    };
  } else {
    // 跨年度区间:匹配月日≥起始月日 或者 ≤结束月日
    birthdayQuery.$expr = {
      $or: [
        {
          $and: [
            { $gte: [{ $month: '$birthDate' }, startMonth] },
            { $or: [{ $ne: [{ $month: '$birthDate' }, startMonth] }, { $gte: [{ $dayOfMonth: '$birthDate' }, startDay] }] }
          ]
        },
        {
          $and: [
            { $lte: [{ $month: '$birthDate' }, endMonth] },
            { $or: [{ $ne: [{ $month: '$birthDate' }, endMonth] }, { $lte: [{ $dayOfMonth: '$birthDate' }, endDay] }] }
          ]
        }
      ]
    };
  }
}

// 执行查询,可合并其他查询条件
const profiles = await Profile.find(birthdayQuery);

简化版方案(用MMDD数值比较)

如果觉得月日拆分判断繁琐,可以将月日转成4位数字(比如05-02转成502),直接比较数值大小:

const getMMDD = (date) => {
  const month = dayjs(date).month() + 1;
  const day = dayjs(date).date();
  return month * 100 + day;
};

const startMMDD = getMMDD(birthDateStart);
const endMMDD = getMMDD(birthDateEnd);

birthdayQuery.$expr = startMMDD <= endMMDD 
  ? { 
      $and: [
        { $gte: [{ $add: [{ $multiply: [{ $month: '$birthDate' }, 100] }, { $dayOfMonth: '$birthDate' }] }, startMMDD] },
        { $lte: [{ $add: [{ $multiply: [{ $month: '$birthDate' }, 100] }, { $dayOfMonth: '$birthDate' }] }, endMMDD] }
      ]
    }
  : { 
      $or: [
        { $gte: [{ $add: [{ $multiply: [{ $month: '$birthDate' }, 100] }, { $dayOfMonth: '$birthDate' }] }, startMMDD] },
        { $lte: [{ $add: [{ $multiply: [{ $month: '$birthDate' }, 100] }, { $dayOfMonth: '$birthDate' }] }, endMMDD] }
      ]
    };

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 19:53:17