问题描述
要求:文档-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 }
]
解决方法
这个要求也可以在逻辑上完成..比如使用findAll获取DocumentsBookdata的列表,然后使用循环过滤并存储每个出版商的图书数量,但这将是一个冗长的方法,因此下面的代码将简单地使用Aggregation获取每个出版商的书目
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;
}
,
您可以如下实现 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;
}
}
然后从您的代码中调用该实用工具类方法,以按指定为group By的字段获取 Count,Min and 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());