Spring中MongoDB查询如何按日期字段的日和月排序(忽略年份)
问题:MongoDB按出生日期的月日排序(忽略无效年份)
需要对MongoDB查询结果按出生日期(dob)字段排序,但该字段存储的年份为无效值(不再要求用户提供出生年份),期望排序效果如下:
1. 2004-03-05 7. 2005-01-28 2. 2001-03-03 2. 2001-03-03 3. 2003-12-08 1. 2004-03-05 4. 2015-10-08 -> 6. 1999-07-16 5. 1999-09-24 5. 1999-09-24 6. 1999-07-16 4. 2015-10-08 7. 2005-01-28 3. 2003-12-08
当前实现是先按sortingField(此处为dob)排序,再按_id保证顺序稳定,代码如下:
List<Sort.Order> sortList = new ArrayList<>(); sortList.add( new Sort.Order( sortDirection.compareToIgnoreCase("d") == 0 ? Sort.Direction.DESC : Sort.Direction.ASC, sortingField)); sortList.add(new Sort.Order(Sort.Direction.ASC, "_id")); query.with(Sort.by(sortList)); List<Customer> customers = mongoTemplate.find(query, Customer.class);
请问是否可以实现按日和月排序的需求?
解决方案
可以实现,以下是两种常用方案,可根据数据量和性能要求选择:
方式一:数据库端聚合排序(推荐,性能更优)
利用MongoDB聚合管道,先从dob字段中提取月份和日期,再基于这两个字段排序,最后返回原文档结构。这种方式在数据库端完成排序,适合大数据量场景。
代码示例:
// 确定排序方向 Sort.Direction dateSortDir = sortDirection.compareToIgnoreCase("d") == 0 ? Sort.Direction.DESC : Sort.Direction.ASC; // 构建聚合管道 Aggregation aggregation = Aggregation.newAggregation( // 投影提取月份、日期及原文档字段 Aggregation.project() .andInclude("_id", "dob" /* 其他需要保留的字段 */) .andExpression("$month", "$dob").as("month") .andExpression("$dayOfMonth", "$dob").as("day"), // 按月份、日期排序,最后按_id保证顺序稳定 Aggregation.sort( dateSortDir, "month", "day", Sort.Direction.ASC, "_id" ), // 移除临时生成的month、day字段,恢复原文档结构 Aggregation.project().andExclude("month", "day") ); // 执行聚合查询 List<Customer> customers = mongoTemplate.aggregate( aggregation, "customer", Customer.class ).getMappedResults();
方式二:内存中排序(适合小数据量)
如果数据量较小,可以先查询所有文档,再在Java内存中通过自定义比较器,仅针对dob的月和日进行排序。
代码示例:
// 先查询所有数据(无需数据库端排序) Query query = new Query(); List<Customer> customers = mongoTemplate.find(query, Customer.class); // 确定最终排序方向 Sort.Direction finalDateSortDir = sortDirection.compareToIgnoreCase("d") == 0 ? Sort.Direction.DESC : Sort.Direction.ASC; // 自定义排序规则:先比月份,再比日期,最后比_id Collections.sort(customers, (c1, c2) -> { LocalDate dob1 = c1.getDob(); LocalDate dob2 = c2.getDob(); // 月份比较 int monthCompare = Integer.compare(dob1.getMonthValue(), dob2.getMonthValue()); if (monthCompare != 0) { return finalDateSortDir == Sort.Direction.ASC ? monthCompare : -monthCompare; } // 日期比较 int dayCompare = Integer.compare(dob1.getDayOfMonth(), dob2.getDayOfMonth()); if (dayCompare != 0) { return finalDateSortDir == Sort.Direction.ASC ? dayCompare : -dayCompare; } // 最后按_id保证排序稳定 return c1.getId().compareTo(c2.getId()); });
内容的提问来源于stack exchange,提问作者LaplacesCat
相关产品推荐
相关产品推荐

