在spring数据mongodb中如何实现聚合的分页

gou*_*ham 4 spring-data-mongodb spring-boot

在使用mongotemplate或mongorepository的spring数据mongodb中,如何实现聚合的分页

Fır*_*ÇÜK 7

除了ssouris解决方案,您还可以使用Pageable类来获得结果.

public Page<UserListItemView> list(final Pageable pageable) {

    final Aggregation agg = newAggregation(
        skip(pageable.getPageNumber() * pageable.getPageSize()),
        limit(pageable.getPageSize())
    );

    final List<UserListItemView> results = mongoTemplate
        .aggregate(agg, User.class, UserListItemView.class)
        .getMappedResults();

    return new PageImpl<>(results, pageable, results.size())
}
Run Code Online (Sandbox Code Playgroud)

  • 在“new PageImpl&lt;&gt;()”中将总计设置为“results.size()”在我看来是错误的。您可能需要执行另一个查询才能获得总结果。 (4认同)

Ste*_*rck 6

这是旧帖子的答案,但我会提供答案,以防其他人在搜索此类内容时出现.

FıratKÜÇÜK之前的解决方案的基础上,将result.size()作为PageImpl构造函数中"total"字段的值,将不会使分页工作正常,嗯,您希望分页工作.它每次都会将总大小设置为页面大小,因此您需要找出查询返回的实际结果总数:

public Page<UserListItemView> list(final Pageable pageable) {
    long total = getCount(<your property name>, <your property value>);

    final Aggregation agg = newAggregation(
        skip(pageable.getPageNumber() * pageable.getPageSize()),
        limit(pageable.getPageSize())
    );

    final List<UserListItemView> results = mongoTemplate
        .aggregate(agg, User.class, UserListItemView.class)
        .getMappedResults();

    return new PageImpl<>(results, pageable, total);
}
Run Code Online (Sandbox Code Playgroud)

现在,获得结果总数的最佳方法是另一个问题,这是我目前正在试图解决的问题.我尝试过的方法(并且它起作用)是几乎运行相同的聚合两次,(一次获得总计数,再次获得分页的实际结果)但仅使用MatchOperation后跟GroupOperation来获取计数:

private long getCount(String propertyName, String propertyValue) {
    MatchOperation matchOperation = match(Criteria.where(propertyName).is(propertyValue));
    GroupOperation groupOperation = group(propertyName).count().as("count");
    Aggregation aggregation = newAggregation(matchOperation, groupOperation);
    return mongoTemplate.aggregate(aggregation, Foo.class, NumberOfResults.class).getMappedResults().get(0).getCount();
}

private class NumberOfResults {
    private int count;

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}
Run Code Online (Sandbox Code Playgroud)

运行几乎相同的查询两次似乎效率低下,但是如果要打印结果,如果您真的希望它的行为像分页一样,则可分页对象必须知道结果的总数.如果有人可以改进我的方法来获得结果总数,那就太棒了!

编辑:这也将提供计数,并且它更简单,因为您不需要包装器对象来保存结果,因此您可以用以下代码块替换整个以前的代码块:

private long getCount(String propertyName, String propertyValue) {
    Query countQuery = new Query(Criteria.where(propertyName).is(propertyValue));
    return mongoTemplate.count(countQuery, Foo.class);
}
Run Code Online (Sandbox Code Playgroud)

  • 尝试使用 PageableExecutionUtils ,您不必另外计数 (2认同)

小智 5

你可以使用MongoTemplate

org.spring.framework.data.mongodb.core.aggregation.Aggregation#skip
        and 
org.springframework.data.mongodb.core.aggregation.Aggregation#limit

Aggregation agg = newAggregation(
        project("tags"),
        skip(10),
        limit(10)
);

AggregationResults<TagCount> results = mongoTemplate.aggregate(agg, "tags", TagCount.class);
List<TagCount> tagCount = results.getMappedResults();
Run Code Online (Sandbox Code Playgroud)


小智 5

根据答案/sf/answers/2784939601/,我为Java编写了代码。

使用聚合组来获取数据的计数和数组以及其他分页信息。

    AggregationOperation group = Aggregation.group().count().as("total")
            .addToSet(pageable.getPageNumber()).as("pageNumber")
            .addToSet(pageable.getPageSize()).as("pageSize")
            .addToSet(pageable.getOffset()).as("offset")
            .push("$$ROOT").as("data");
Run Code Online (Sandbox Code Playgroud)

使用聚合项目根据分页信息进行切片。

    AggregationOperation project = Aggregation.project()
            .andInclude("pageSize", "pageNumber", "total", "offset")
            .and(ArrayOperators.Slice.sliceArrayOf("data").offset((int) pageable.getOffset()).itemCount(pageable.getPageSize()))
            .as("data");
Run Code Online (Sandbox Code Playgroud)

使用mongo模板进行聚合。

    Aggregation aggr = newAggregation(group, project);
    CustomPage page = mongoTemplate.aggregate(aggregation, Foo.class, CustomPage.class).getUniqueMappedResult();
Run Code Online (Sandbox Code Playgroud)

创建自定义页面。

    public class CustomPage {
        private long pageSize;
        private long pageNumber;
        private long offset;
        private long total;
        private List<Foo> data;
    }
Run Code Online (Sandbox Code Playgroud)