MongoDB查询:按枚举状态优先级随机选取3条文档的实现方法
按状态优先级随机选取MongoDB文档的实现方案
需求是随机选取3条文档,但需严格遵循NEW > IN_PROGRESS > PAUSED的状态优先级:优先从NEW状态中选取,若NEW数量不足3条,再从IN_PROGRESS中补充,仍不足则从PAUSED中补全。
原代码直接使用sample阶段无法实现优先级逻辑,需通过聚合管道的多阶段处理来满足需求,以下是修改后的Kotlin实现:
mongoTemplate.aggregate<Book, Book>( newAggregation( // 筛选目标状态的文档 match(where("status").`in`(BookStatus.allToBeRead)), // 按状态分桶,每个桶内随机采样足够数量的文档 facet( AggregationOperation { context -> Document("NEW", listOf( Document("\$match", Document("status", BookStatus.NEW.name)), Document("\$sample", Document("size", 3)) )) }, AggregationOperation { context -> Document("IN_PROGRESS", listOf( Document("\$match", Document("status", BookStatus.IN_PROGRESS.name)), Document("\$sample", Document("size", 3)) )) }, AggregationOperation { context -> Document("PAUSED", listOf( Document("\$match", Document("status", BookStatus.PAUSED.name)), Document("\$sample", Document("size", 3)) )) } ), // 将分桶结果展开为单个文档,允许空值避免无对应状态时中断 unwind("\$NEW"), unwind("\$IN_PROGRESS", true), unwind("\$PAUSED", true), // 合并所有候选文档,并标记优先级 project() .and("NEW").as("doc").whenNull("IN_PROGRESS").whenNull("PAUSED") .and(0).as("priority").when(where("NEW").exists(true)) .and(1).as("priority").when(where("IN_PROGRESS").exists(true)) .and(2).as("priority").when(where("PAUSED").exists(true)), // 按优先级升序排序,保证高优先级文档在前 sort(Sort.by(Sort.Order.asc("priority"))), // 取前3条文档 limit(3), // 恢复原始文档结构 replaceRoot("\$doc") ) )
代码逻辑说明
- 分桶采样:通过
facet将三个状态的文档分别处理,每个状态采样最多3条,确保有足够的候选文档。 - 合并与优先级标记:将分桶结果展开后,合并为统一的文档流,并为不同状态标记优先级(NEW=0,IN_PROGRESS=1,PAUSED=2)。
- 排序与截取:按优先级升序排序,确保高优先级文档排在前面,最后截取前3条即可满足需求。
示例验证
- 示例1:当
NEW状态文档≥3条时,结果全部为随机选取的NEW文档。 - 示例2:当
NEW只有2条时,会从IN_PROGRESS中随机补1条,最终结果为2条NEW+1条IN_PROGRESS。
内容的提问来源于stack exchange,提问作者inconnu
相关产品推荐
相关产品推荐

