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

Spring Boot中按MongoDB文档Set类型属性长度排序获取电影文档列表

看来你遇到了把likes/hates改成Set类型后排序失效的问题,同时还想避免写一堆重复的方法对吧?我来给你梳理下解决方案:

解决方案:按MongoDB集合字段大小排序并返回完整文档

首先先解决你之前聚合查询不生效的核心问题:你的$size表达式里的$likes缺少单引号,应该写成'$likes',否则MongoDB无法正确识别为字段引用,导致计数计算错误,自然排序逻辑失效。

接下来提供两种更优的实现方式,既可以返回完整的MovieDocument,又能避免编写重复的方法:

方式一:使用带参数的@Aggregation注解(简化版)

你可以通过参数化排序方向,用单个方法处理同一字段的升序/降序需求。同时通过$addFields(或$set)添加临时计数字段,排序后可选移除该字段:

修改后的Repository方法

@Repository
public interface MoviesRepository extends MongoRepository<MovieDocument, String> {
    @Aggregation(pipeline = {
        "{$addFields: { like_count: { $size: '$likes' } }}",
        "{$sort: { like_count: ?0 }}",
        "{$project: { like_count: 0 }}" // 可选:移除临时计数字段,返回原始文档结构
    })
    List<MovieDocument> getSortedByLikes(int sortOrder);

    // 同理针对hates字段
    @Aggregation(pipeline = {
        "{$addFields: { hate_count: { $size: '$hates' } }}",
        "{$sort: { hate_count: ?0 }}",
        "{$project: { hate_count: 0 }}"
    })
    List<MovieDocument> getSortedByHates(int sortOrder);
}

调用示例

// 按点赞数降序
List<MovieDocument> movies = moviesRepository.getSortedByLikes(-1);
// 按点踩数升序
List<MovieDocument> movies = moviesRepository.getSortedByHates(1);

传入-1表示降序,1表示升序,一个方法就能覆盖两种排序方向。

方式二:使用MongoTemplate动态构建聚合管道(推荐,最高扩展性)

如果想要完全复用你之前的getSortedMovies方法签名,支持动态选择排序字段和方向,使用MongoTemplate动态构建聚合管道是最佳方案。这样无需编写多个Repository方法,逻辑更集中:

1. 在Service中实现动态排序逻辑

@Service
public class MovieService {
    private final MongoTemplate mongoTemplate;

    public MovieService(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    public List<MovieDocument> getSortedMovies(SortProperty sortBy, Order order) {
        // 定义临时计数字段名和目标集合字段名
        String countField = sortBy == SortProperty.likes ? "like_count" : "hate_count";
        String targetField = sortBy.toString();
        int sortDirection = order == Order.desc ? -1 : 1;

        // 构建聚合管道
        Aggregation aggregation = Aggregation.newAggregation(
            // 添加临时计数字段:计算集合大小
            Aggregation.addFields()
                .addField(countField)
                .withValue(AggregationExpression.from("{ $size: '$" + targetField + "' }"))
                .build(),
            // 按计数字段排序
            Aggregation.sort(Sort.by(order, countField)),
            // 可选:移除临时计数字段,保持原始文档结构
            Aggregation.project().andExclude(countField)
        );

        // 执行聚合并映射结果
        AggregationResults<MovieDocument> results = mongoTemplate.aggregate(
            aggregation,
            MovieDocument.class, // 自动映射到对应集合
            MovieDocument.class
        );

        return results.getMappedResults();
    }
}

2. 保留原有的枚举类(假设你已定义)

public enum SortProperty {
    likes, hates
}

public enum Order {
    asc, desc
}

这种方式完全复用了你之前的方法调用逻辑,客户端传入sortBy和order即可实现动态排序,无需修改调用代码,扩展性拉满。

总结

  • 之前的代码不生效,核心原因是$size表达式里的字段引用缺少单引号,导致MongoDB无法正确计算集合大小
  • 若追求简单,用带参数的@Aggregation注解可以减少重复代码
  • 若要完全复用原有调用逻辑,MongoTemplate动态构建管道是最优解

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 14:02:29