如何用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
相关产品推荐
相关产品推荐

