【问题标题】:How to get list of data containing count of a field using Aggregation and Criteria in Spring Boot with MangoDB如何在带有 MangoDB 的 Spring Boot 中使用聚合和条件获取包含字段计数的数据列表
【发布时间】:2025-11-27 01:10:01
【问题描述】:

要求:documents-bookdata 集合可能有多个具有相同 bookPublisherName 但不同 bookName 的对象。意味着多本书可以有同一个出版商,因此需要提取每个出版商的图书数量。

模型类:

@Document(collection = "documents-bookdata")
public class DocumentsBookdata {

    @Id
    private String bookId;
    private String bookName;
    private String bookPublisherName;
//setters and getters
}

响应格式 pojo

public class PublisherBookCount {

private String bookPublisherName;
private int bookCount;
//setters and getters
}

响应格式

 [
 { "bookPublisherName": "docClassA", "bookCount": 3023 },
 { "bookPublisherName": "docClassB", "bookCount": 4100 }
 ]

【问题讨论】:

    标签: java mongodb spring-boot spring-data-mongodb


    【解决方案1】:

    这个要求也可以在逻辑上完成......就像使用 findAll 获取 DocumentsBookdata 列表,然后使用循环过滤它并存储每个出版商的书籍数量。但这将是一个冗长的方法。所以下面的代码将简单地使用聚合获得每个出版商的图书数量

    public List<PublisherBookCount> getBookCOunt(){
        List<PendingDocumentCount> list = new ArrayList<>();
        PublisherBookCount count = null;
        Aggregation aggregation = Aggregation.newAggregation( Aggregation.project("bookPublisherName").andExclude("_id"),
                                                                       Aggregation.sortByCount("bookPublisherName"));
        List<Document> docs=  mongoTemplate.aggregate(aggregation, "documents-bookdata", Document.class).getMappedResults();
              for(Document doc : docs) {
              count = new PublisherBookCount();
                  count.setBookPublisherName(doc.get("bookPublisherName").toString());
                  count.setBookCount(Integer.parseInt(doc.get("count").toString()));
                  list.add(count);
              }
              
              return list;
          }
    

    【讨论】:

      【解决方案2】:

      您可以为 Group by 实现 Utility 类,如下所示。

      public class GroupByUtility<T> implements Consumer<T> {
          public static <T extends Comparable<? super T>> Collector<T, ?, GroupByUtility<T>>
          statistics() {
              return statistics(Comparator.<T>naturalOrder());
          }
      
          public static <T> Collector<T, ?, GroupByUtility<T>>
          statistics(Comparator<T> comparator) {
              Objects.requireNonNull(comparator);
              return Collector.of(() -> new GroupByUtility<>(comparator),
                      GroupByUtility::accept, GroupByUtility::merge);
          }
      
          private final Comparator<T> c;
          private T min, max;
          private long count;
      
          public GroupByUtility(Comparator<T> comparator) {
              c = Objects.requireNonNull(comparator);
          }
      
          public void accept(T t) {
              if (count == 0) {
                  count = 1;
                  min = t;
                  max = t;
              } else {
                  if (c.compare(min, t) > 0) min = t;
                  if (c.compare(max, t) < 0) max = t;
                  count++;
              }
          }
      
          public GroupByUtility<T> merge(GroupByUtility<T> s) {
              if (s.count > 0) {
                  if (count == 0) {
                      count = s.count;
                      min = s.min;
                      max = s.max;
                  } else {
                      if (c.compare(min, s.min) > 0) min = s.min;
                      if (c.compare(max, s.max) < 0) max = s.max;
                      count += s.count;
                  }
              }
              return this;
          }
      
          public long getCount() {
              return count;
          }
      
          public T getMin() {
              return min;
          }
      
          public T getMax() {
              return max;
          }
      
      }
      

      然后从您的代码中调用该实用程序类方法以获取 Count,Min and Max 按字段指定为 group By

              List<DocumentsBookdata> documentsBookdata=new ArrayList();
              Map<Long, GroupByUtility<DocumentsBookdata>> maxMap = documentsBookdata.stream()
                      .collect(Collectors.groupingBy(o -> o.getBookId(),
                              GroupByUtility.statistics(Comparator.comparing(o -> o.getPublisherName()))));
              return maxMap.entrySet().stream().map(obj->obj.getValue().getCount()).collect(Collectors.toList());
      

      【讨论】:

      • 正如我所提到的,我需要聚合方法