在Spring Data MongoDB Aggregation中对数组进行分组后,Count操作返回1而不是0

问题描述

我需要使用具有以下模型的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()原则进行过滤的不同数量的图书。

假设我有四本已出版的书,普通用户添加了一本,隐藏的又一本。

  1. 管理员应该了解所有这些信息,因此他会将booksCount视为6
  2. 普通用户只能看到自己发布或添加内容,因此他会将booksCount视为5
  3. 将来还会有其他情况。

我想到了这样的聚合:

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()操作。

  1. 如果books数组大小为0,则始终返回1。
  2. 如果书籍数组的大小大于0,则返回正确的数量
  3. 我尝试使用newBuilder(GroupOps.SUM,null,0)代替count(),但是现在它总是返回0。
  4. 如果我使用newBuilder(GroupOps.SUM,2),它将返回size + 2。我不知道发生了什么。

我的问题:

  1. 有人可以告诉我我在做什么错以及如何纠正吗?
  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

工作Mongo playground with correct answer