问题描述
我需要使用具有以下模型的Spring Data MongoDB创建高级聚合:
@Getter
@Setter
@Document
public class Library {
@Id
@JsonSerialize(using = ToStringSerializer.class)
private ObjectId id;
private Address address;
private String workingHours;
...
}
@Getter
@Setter
@Document
public class Book {
@Id
@JsonSerialize(using = ToStringSerializer.class)
private ObjectId id;
private Boolean published;
private Boolean hidden;
private String title;
@DBRef
@NotNull
private Library library;
...
}
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("5f45440ee89590218e83a697"),"workingHours" : "8:00 PM - 8:00 AM","address" : DBRef("addresses",ObjectId("5f4544198da452a5523e3d11"))
}
图书收藏:
{
"_id" : ObjectId("5f454423be823729015661ed"),"published": true,"hidden": false,"title": "The Hobbit,or There and Back Again"
"library" : DBRef("libraries",ObjectId("5f45440ee89590218e83a697"))
},{
"_id" : ObjectId("5f45445b876d08649b88ed5a"),"title": "Harry Potter and the Philosopher's Stone"
"library" : DBRef("libraries",{
"_id" : ObjectId("5f45446c7e33ca70363f629a"),"title": "Harry Potter and the Cursed Child"
"library" : DBRef("libraries",{
"_id" : ObjectId("5f45447285f9b3e4cb8739ad"),"title": "Fantastic Beasts and Where to Find Them"
"library" : DBRef("libraries",{
"_id" : ObjectId("5f45449fc121a20afa4fbb96"),"published": false,"title": "Universal Parks & Resorts"
"library" : DBRef("libraries",{
"_id" : ObjectId("5f4544a5f13839bbe89edb23"),"hidden": true,"title": "Ministry of Dawn"
"library" : DBRef("libraries",ObjectId("5f45440ee89590218e83a697"))
}
功能:
- 用户必须能够按每个字段进行过滤。 ->那对我来说不是问题。根据传递的参数,我将创建
Criteria
并使用Aggregation.match()
。 - 根据用户的上下文,我必须返回可以基于
startsWith()
或like()
原则进行过滤的不同数量的图书。 ->这是个问题。
假设我有四本已出版的书,普通用户又添加了一本,隐藏的又一本。
- 管理员应该了解所有这些信息,因此他会将
booksCount
视为6
。 - 普通用户只能看到自己发布或添加的内容,因此他会将
booksCount
视为5
。 - 未登录的用户只会看到已发布的用户,因此他会将
booksCount
视为4
。 - 将来还会有其他情况。
Criteria criteria = Criteria.where("_id").ne(null).and("address.city").is("Chicago");
if (!isAdministrator()) {
criteria = criteria.and("published").is(Boolean.TRUE);
}
MatchOperation matchOperation = Aggregation.match(criteria);
LookupOperation lookupOperation = LookupOperation.newLookup().from("books").localField("id").foreignField("library.$id").as("books");
UnwindOperation unwindOperation = Aggregation.unwind("books");
CountOperation countOperation = Aggregation.count().as("booksCount");
Aggregation aggregation = Aggregation.newAggregation(matchOperation,lookupOperation,unwindOperation,countOperation);
mongoTemplate.aggregate(aggregation,"libraries",Document.class).getRawResults().getInteger("booksCount");
起初我以为我会使用LookupOperation
,但是它不能正常工作(它会独立于ObjectId
来获取藏书中的所有书籍)。不幸的是,我遇到一个问题,除了在DBRef
阶段,我们无法在聚合管道中使用$match
。 Here is the description of the problem。
我阅读了第二篇文章中的解释,但是我不知道如何使用Spring Data MongoDB通过地图操作实现这种高级投影。此外,我希望能够按照第二点中的描述按此值进行过滤。
我的问题是:
- 如何使用Spring Data MongoDB实现这种行为(我也许可以稍微调整一下版本)?
- 如果我们执行此操作,是否可以按照说明中所述对
booksCount
应用适当的过滤器? - 是否存在使用其他库,框架或功能来实现这种行为的另一种方法?我只考虑自定义DTO,查询所有现有库,遍历它们并基于传递的参数查询
booksCount
。但这并不能解决过滤和分页问题。
谢谢。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)