如何在 Spring Boot with MangoDB 中使用聚合和条件获取包含字段计数的数据列表
How to get list of data containing count of a field using Aggregation and Criteria in Spring Boot with MangoDB
要求: documents-bookdata 集合可能有多个 bookPublisherName 相同但 bookName 不同的对象。意味着多本书可以有相同的出版商,因此需要提取每个出版商的图书数量。
型号class:
@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 }
]
您可以为 Group by
实现 Utility class,如下所示。
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;
}
}
然后从您的代码中调用该实用程序 class 方法以按字段指定为组
获取 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());
这个要求也可以在逻辑上完成..比如使用 findAll 获取 DocumentsBookdata 列表,然后使用循环过滤它并存储每个 publisher.But 的书籍数量,这将是一个冗长的 approach.SO下面的代码将简单地使用聚合来获取每个出版商的图书数量
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;
}
要求: documents-bookdata 集合可能有多个 bookPublisherName 相同但 bookName 不同的对象。意味着多本书可以有相同的出版商,因此需要提取每个出版商的图书数量。
型号class:
@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 }
]
您可以为 Group by
实现 Utility class,如下所示。
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;
}
}
然后从您的代码中调用该实用程序 class 方法以按字段指定为组
获取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());
这个要求也可以在逻辑上完成..比如使用 findAll 获取 DocumentsBookdata 列表,然后使用循环过滤它并存储每个 publisher.But 的书籍数量,这将是一个冗长的 approach.SO下面的代码将简单地使用聚合来获取每个出版商的图书数量
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;
}