问题描述
我需要使用具有以下模型的Spring Data MongoDB创建高级聚合:
@Getter
@Setter
@Document
public class City {
@Id
@JsonSerialize(using = ToStringSerializer.class)
private ObjectId id;
private Address description;
private String name;
...
}
@Getter
@Setter
@Document
public class Library {
@Id
@JsonSerialize(using = ToStringSerializer.class)
private ObjectId id;
private Address address;
private String workingHours;
@JsonSerialize(using = ToStringSerializer.class)
private ObjectId cityId;
...
}
@Getter
@Setter
@Document
public class Book {
@Id
@JsonSerialize(using = ToStringSerializer.class)
private ObjectId id;
private Boolean published;
private Boolean hidden;
private String title;
@JsonSerialize(using = ToStringSerializer.class)
private ObjectId libraryId;
...
}
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.2.0</version>
</dependency>
城市集合:
{
"_id" : ObjectId("5f47878c95f47e209402fe15"),"name" : "Warsaw","description" : "Sample description"
}
{
"_id" : ObjectId("5f4787918b343fff4f52c270"),"name" : "Chicago","description" : "Sample description"
}
图书馆藏书:
{
"_id" : ObjectId("5f45440ee89590218e83a697"),"workingHours" : "8:00 PM - 8:00 AM","address" : DBRef("addresses",ObjectId("5f4544198da452a5523e3d11")),"cityId": ObjectId("5f47878c95f47e209402fe15")
},{
"_id" : ObjectId("5f478725d1507323a80efa31"),ObjectId("5f4787379e72f882e4d26912")),{
"_id" : ObjectId("5f47872f7c4872d4983961f5"),ObjectId("5f47873d5ddedadb3d6ddd6e")),"cityId": ObjectId("5f4787918b343fff4f52c270")
}
图书收藏:
{
"_id" : ObjectId("5f454423be823729015661ed"),"published": true,"hidden": false,"title": "The Hobbit,or There and Back Again"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},{
"_id" : ObjectId("5f45445b876d08649b88ed5a"),"title": "Harry Potter and the Philosopher's Stone"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},{
"_id" : ObjectId("5f45446c7e33ca70363f629a"),"title": "Harry Potter and the Cursed Child"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},{
"_id" : ObjectId("5f45447285f9b3e4cb8739ad"),"title": "Fantastic Beasts and Where to Find Them"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},{
"_id" : ObjectId("5f45449fc121a20afa4fbb96"),"published": false,"title": "Universal Parks & Resorts"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},{
"_id" : ObjectId("5f4544a5f13839bbe89edb23"),"hidden": true,"title": "Ministry of Dawn"
"libraryId": ObjectId("5f45440ee89590218e83a697")
}
根据用户的上下文,我必须返回城市,该城市的图书馆和书籍数量可以根据startsWith()
或like()
原则进行过滤。
假设我在一个城市有2个图书馆,在另一个城市有1个图书馆。
- 我需要先使用查找计数库,然后返回
librariesCount
-分别为2
和1
。 - 我需要在每个图书馆中获取/查找图书,然后将它们计为'booksCount',然后乘以
librariesCount
以得出城市中booksCount
的总数(我们将其称为{{1 }}。
我想到了这样的聚合:
cityBooksCount
借助其中一位stackoverflow用户的帮助,我得以以适当的方式获得Criteria criteria = Criteria.where("_id");
MatchOperation matchOperation = Aggregation.match(criteria);
LookupOperation lookupOperation = LookupOperation.newLookup().from("libraries").localField("_id").foreignField("cityId").as("libraries");
UnwindOperation unwindOperation = Aggregation.unwind("libraries",true);
LookupOperation secondLookupOperation = LookupOperation.newLookup().
from("books").
localField("libraryIdArray").
foreignField("libraryId").
as("books");
UnwindOperation secondUnwindOperation = Aggregation.unwind("books",true);
AggregationOperation group = Aggregation.group("_id")
.first("_id").as("id")
.first("name").as("name")
.first("description").as("description")
.push("libraries").as("libraries")
.push("books").as("books");
ProjectionOperation projectionOperation = Aggregation.project("id","description","name")
.and(VariableOperators.mapItemsOf(ConditionalOperators.ifNull("libraries").then(Collections.emptyList()))
.as("library").andApply(aggregationOperationContext -> {
Document document = new Document();
document.append("id","$$library._id");
return document;
})).as("libraryIdArray")
.and(ConvertOperators.valueOf(ArrayOperators.Size.lengthOfArray(ConditionalOperators.ifNull("libraries").then(Collections.emptyList()))).convertToString()).as("librariesCount")
.and(ConvertOperators.valueOf(ArrayOperators.Size.lengthOfArray(ConditionalOperators.ifNull("books").then(Collections.emptyList()))).convertToString()).as("cityBooksCount");
Aggregation aggregation = Aggregation.newAggregation(matchOperation,lookupOperation,unwindOperation,secondLookupOperation,secondUnwindOperation,group,projectionOperation);
mongoTemplate.aggregate(aggregation,"cities",Document.class).getRawResults().get("results");
。不幸的是,librariesCount
始终指向cityBooksCount
。
我对MongoDB不太熟悉,但是我知道0
operation is possible on array,所以我尝试将库数组映射到$lookup
的列表,但是它不能正常工作。可能我做错了,但我不知道问题出在哪里。我得到了适当数量的具有其他预计领域的城市。
谁能告诉我我在做什么错以及如何纠正它?
谢谢。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)