导读:本期聚焦于小伙伴创作的《如何使用Mongoose和MongoDB聚合查询跨年份生日范围忽略年份》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何使用Mongoose和MongoDB聚合查询跨年份生日范围忽略年份》有用,将其分享出去将是对创作者最好的鼓励。

在用户管理相关的业务场景中,经常需要实现忽略年份查询生日范围的需求,比如统计生日在10月1日到次年2月1日之间的用户,或者筛选本月过生日的用户。使用Mongoose操作MongoDB时,普通的日期查询会包含年份信息,无法直接满足忽略年份的查询要求,需要借助MongoDB的聚合查询能力来实现。

如何使用Mongoose和MongoDB聚合查询跨年份生日范围忽略年份

需求分析与实现思路

要实现忽略年份的生日范围查询,核心是把用户生日中的月份和日期提取出来,转换成可比较的数值,再结合范围条件进行筛选。具体步骤如下:

  • 使用聚合管道的$addFields阶段,提取生日字段的月份和日期,组合成MM-DD格式的字符串或者对应的数值
  • 将查询的起始日期和结束日期也转换成相同的MM-DD格式
  • 处理跨年份的范围场景,比如查询12月到次年2月的生日,需要拆分条件分别匹配
  • 使用$match阶段完成最终的筛选

数据模型定义

首先定义用户的Mongoose模型,其中包含生日字段,类型为Date:

const mongoose = require('mongoose');
const { Schema } = mongoose;

// 用户模型定义
const userSchema = new Schema({
  name: String,
  birthday: Date // 存储用户的完整生日日期,包含年月日
});

const User = mongoose.model('User', userSchema);

聚合查询实现

非跨年份的生日范围查询

如果查询的范围在同一年,比如查询生日在3月15日到6月20日之间的用户,实现逻辑如下:

/**
 * 查询生日在指定月日范围内的用户,范围不跨年份
 * @param {string} start - 起始月日,格式MM-DD,比如03-15
 * @param {string} end - 结束月日,格式MM-DD,比如06-20
 * @returns {Promise<Array>} 匹配的用户列表
 */
async function queryBirthdayInRange(start, end) {
  const result = await User.aggregate([
    // 新增字段存储生日的月日字符串
    {
      $addFields: {
        birthdayMD: {
          $dateToString: {
            format: '%m-%d',
            date: '$birthday'
          }
        }
      }
    },
    // 筛选月日在范围内的文档
    {
      $match: {
        birthdayMD: {
          $gte: start,
          $lte: end
        }
      }
    },
    // 移除临时添加的字段
    {
      $project: {
        birthdayMD: 0
      }
    }
  ]);
  return result;
}

跨年份的生日范围查询

当查询范围跨年份时,比如查询12月1日到次年2月28日的生日,直接比较MM-DD字符串会失效,需要拆分条件:要么月日大于等于12-01,要么月日小于等于02-28。实现代码如下:

/**
 * 查询生日在指定月日范围内的用户,支持跨年份
 * @param {string} start - 起始月日,格式MM-DD,比如12-01
 * @param {string} end - 结束月日,格式MM-DD,比如02-28
 * @returns {Promise<Array>} 匹配的用户列表
 */
async function queryBirthdayCrossYear(start, end) {
  // 将起始和结束的月日转换成数值,方便比较
  const startNum = parseInt(start.replace('-', ''), 10);
  const endNum = parseInt(end.replace('-', ''), 10);
  let matchCondition = {};

  if (startNum <= endNum) {
    // 不跨年份的场景
    matchCondition = {
      $addFields: {
        birthdayMDNum: {
          $toInt: {
            $replaceAll: {
              input: { $dateToString: { format: '%m-%d', date: '$birthday' } },
              find: '-',
              replacement: ''
            }
          }
        }
      },
      $match: {
        birthdayMDNum: { $gte: startNum, $lte: endNum }
      }
    };
  } else {
    // 跨年份的场景,比如12-01到02-28,匹配大于等于12-01或者小于等于02-28
    matchCondition = {
      $addFields: {
        birthdayMDNum: {
          $toInt: {
            $replaceAll: {
              input: { $dateToString: { format: '%m-%d', date: '$birthday' } },
              find: '-',
              replacement: ''
            }
          }
        }
      },
      $match: {
        $or: [
          { birthdayMDNum: { $gte: startNum } },
          { birthdayMDNum: { $lte: endNum } }
        ]
      }
    };
  }

  const pipeline = [
    matchCondition.$addFields ? matchCondition : null,
    matchCondition.$match ? matchCondition : null,
    // 移除临时字段
    {
      $project: {
        birthdayMDNum: 0
      }
    }
  ].filter(Boolean);

  const result = await User.aggregate(pipeline);
  return result;
}

调用示例

实际使用时的调用方式如下:

// 查询生日在3月15日到6月20日的用户
queryBirthdayInRange('03-15', '06-20').then(users => {
  console.log('范围内用户:', users);
});

// 查询生日在12月1日到次年2月28日的用户(跨年份)
queryBirthdayCrossYear('12-01', '02-28').then(users => {
  console.log('跨年份范围内用户:', users);
});

注意事项

  • 生日字段需要保证存储的是正确的Date类型,如果是字符串类型需要先转换
  • 聚合查询中的日期相关操作符依赖MongoDB的版本,建议使用4.0及以上版本
  • 如果数据量较大,可以对生日字段建立索引提升查询效率,不过聚合管道中的临时字段无法直接使用索引,需要结合实际场景优化
  • 月份和日期的格式需要统一为MM-DD,避免个位数月日导致比较错误

MongooseMongoDB聚合查询生日范围查询修改时间:2026-06-14 02:39:42

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。