How to get list of data containing count of a field using Aggregation and Criteria in Spring Boot with MangoDB

huangapple go评论76阅读模式
英文:

How to get list of data containing count of a field using Aggregation and Criteria in Spring Boot with MangoDB

问题

**需求** "documents-bookdata" 集合可能有多个具有相同 bookPublisherName 但书名不同的对象这意味着多本书可以有相同的出版商因此需要提取每个出版商的书籍数量

**模型类**

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

    @Id
    private String bookId;
    private String bookName;
    private String bookPublisherName;
    // 设置器和获取器
}

响应格式 POJO:

public class PublisherBookCount {

    private String bookPublisherName;
    private int bookCount;
    // 设置器和获取器
}

响应格式:

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

<details>
<summary>英文:</summary>

**Requirement:** documents-bookdata collection may have multiple objects with same bookPublisherName but different bookName. Means multiple books can have same publisher so need to extract count of books per publisher . 

**Model class:**

    @Document(collection = &quot;documents-bookdata&quot;)
    public class DocumentsBookdata {
    
    	@Id
    	private String bookId;
    	private String bookName;
    	private String bookPublisherName;
    //setters and getters
    }

**Response format pojo**

    public class PublisherBookCount {
    
    private String bookPublisherName;
    private int bookCount;
    //setters and getters
    }

**Response Format**

     [
     { &quot;bookPublisherName&quot;: &quot;docClassA&quot;, &quot;bookCount&quot;: 3023 },
     { &quot;bookPublisherName&quot;: &quot;docClassB&quot;, &quot;bookCount&quot;: 4100 }
     ]





</details>


# 答案1
**得分**: 1

这个需求也可以通过逻辑方式完成,比如使用findAll获取DocumentsBookdata列表,然后使用循环进行过滤并存储每个出版商的书籍数量。但这将是一种冗长的方法。因此,下面的代码将简单地使用聚合来获取每个出版商的书籍数量。

```java
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;
}
英文:

This requirement can also be done logically ..like get the list of DocumentsBookdata using findAll and than filter it using loop and store the count for books per publisher.But that would be a lengthy approach.SO below code will simply use Aggregation to get the book cout per publisher

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

答案2

得分: 0

您可以按照以下方式实现用于**分组(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<>(), 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和Max**。

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());

请注意,由于您要求只返回翻译内容,上述内容是经过翻译的版本。如果您有任何其他问题或需要进一步的帮助,请随时提问。

英文:

You can implement Utility class for Group by as below.

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

And from your code, call that utility class method to get Count,Min and Max by field specify as group By

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

huangapple
  • 本文由 发表于 2020年8月18日 19:09:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/63467330.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定