问题描述
我需要使用具有以下模型的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;
@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("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"
"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()
原则进行过滤的不同数量的图书。
假设我有四本已出版的书,普通用户又添加了一本,隐藏的又一本。
我想到了这样的聚合:
Criteria criteria = Criteria.where("_id").ne(null).and("address.city").is("Chicago");
MatchOperation matchOperation = Aggregation.match(criteria);
LookupOperation lookupOperation = LookupOperation.newLookup().from("books").localField("_id").foreignField("topicId").as("books");
UnwindOperation unwindOperation = Aggregation.unwind("books",true);
MatchOperation secondMatchOperation = Aggregation.match(Criteria.where("books.published").is(Boolean.TRUE).orOperator(Criteria.where("creator.userId").is(context.getUserId()));
Aggregationoperation group = Aggregation.group("_id")
.first("_id").as("id")
.first("published").as("published")
.first("title").as("title")
.push("books").as("books").count().as("booksCount");
Aggregation aggregation = !isAdministrator() ?
Aggregation.newAggregation(matchOperation,lookupOperation,unwindOperation,secondMatchOperation,group) :
Aggregation.newAggregation(matchOperation,group);
mongoTemplate.aggregate(aggregation,"libraries",Document.class).getRawResults().get("results");
一切正常,而不是count()
操作。
- 如果books数组大小为0,则始终返回1。
- 如果书籍数组的大小大于0,则返回正确的数量。
- 我尝试使用
newBuilder(GroupOps.SUM,null,0)
代替count()
,但是现在它总是返回0。 - 如果我使用
newBuilder(GroupOps.SUM,2)
,它将返回size + 2
。我不知道发生了什么。
我的问题:
- 有人可以告诉我我在做什么错以及如何纠正吗?
- 此外,我需要将“ booksCount”从
Integer
解析为String
。小组赛有可能吗?
谢谢。
解决方法
发生这种情况的原因是 SELECT [o].[Id],[o].[TypeObjectId],[o0].[Id],[o0].[AttributeValue],[o0].[ObjectId],[o0].[TypeObjectAttributeId],[t].[Id],[t].[AttributeId],[t].[TypeObjectId],[t].[Unicity],[a].[Id],[a].[Description],[a].[Name],[a].[Type]
FROM [ru].[Object] AS [o]
INNER JOIN [ru].[ObjectTypeObjectAttribute] AS [o0] ON [o].[Id] = [o0].[ObjectId]
INNER JOIN [ru].[TypeObjectAttribute] AS [t] ON [o0].[TypeObjectAttributeId] = [t].[Id]
INNER JOIN [ru].[Attribute] AS [a] ON [t].[AttributeId] = [a].[Id]
INNER JOIN [ru].[Attribute] AS [a0] ON [t].[AttributeId] = [a0].[Id]
ORDER BY [a0].[Name]
。没有连接时,除非您将其设置为Aggregation.unwind("books",true);
,否则该语句将保留为文档。默认行为是Aggregation.unwind("books")
。然后,当您计数时,该文档将被计为文档。这就是为什么它为您提供false
作为输出的原因。 Example with wrong output
所以您可以做的是,您可以在下一阶段计算尺寸。
1