在Spring数据MongoDB聚合中分组数组后计数操作returns1而不是0
Count operation returns 1 instead of 0 after grouping array in Spring Data MongoDB Aggregation
我需要使用具有这样模型的 Spring 数据 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"),
"published": true,
"hidden": false,
"title": "Harry Potter and the Philosopher's Stone"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},
{
"_id" : ObjectId("5f45446c7e33ca70363f629a"),
"published": true,
"hidden": false,
"title": "Harry Potter and the Cursed Child"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},
{
"_id" : ObjectId("5f45447285f9b3e4cb8739ad"),
"published": true,
"hidden": false,
"title": "Fantastic Beasts and Where to Find Them"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},
{
"_id" : ObjectId("5f45449fc121a20afa4fbb96"),
"published": false,
"hidden": false,
"title": "Universal Parks & Resorts"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},
{
"_id" : ObjectId("5f4544a5f13839bbe89edb23"),
"published": false,
"hidden": true,
"title": "Ministry of Dawn"
"libraryId": ObjectId("5f45440ee89590218e83a697")
}
根据用户的上下文,我必须 return 可以根据 startsWith()
或 like()
原则过滤不同数量的书籍。
假设我有4本已出版的书,一本是普通用户添加的,一本是隐藏的。
- 管理员应该知道所有这些,因此他会将
booksCount
视为 6
。
- 普通用户只能看到自己发布或添加的内容,因此他会看到
booksCount
为 5
。
- 以后可能还有一些其他条件。
我想出了这样的聚合:
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, lookupOperation, unwindOperation, group);
mongoTemplate.aggregate(aggregation, "libraries", Document.class).getRawResults().get("results");
一切正常,而不是 count()
操作。
- 如果书籍数组大小为 0,它总是 returns 1.
- 如果书籍数组大小大于 0,则 return 是合适的数量。
- 我试过使用
newBuilder(GroupOps.SUM, null, 0)
而不是 count()
,但现在总是 return 0.
- 如果我使用
newBuilder(GroupOps.SUM, null, 2)
它 returns size + 2
。不知道怎么回事
我的问题:
- 谁能告诉我我做错了什么以及如何改正?
- 此外,我需要将“booksCount”从
Integer
解析为 String
。小组赛有可能吗?
提前致谢。
它的发生是因为 Aggregation.unwind("books", true);
。当没有连接时,除非你把它做成Aggregation.unwind("books")
,否则这条语句会保留为文档。默认行为是 false
。那么当你计数的时候,这个文件就被算作一个文件。这就是它为您提供 1
作为输出的原因。 Example with wrong output
所以你可以做的是,你可以在下一阶段计算大小。
project("_id", "published", "title", "books")
.and(ArrayOperators.Size.lengthOfArray(ConditionalOperators.ifNull("books").then(Collections.emptyList()))).as("booksCount")
我需要使用具有这样模型的 Spring 数据 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"),
"published": true,
"hidden": false,
"title": "Harry Potter and the Philosopher's Stone"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},
{
"_id" : ObjectId("5f45446c7e33ca70363f629a"),
"published": true,
"hidden": false,
"title": "Harry Potter and the Cursed Child"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},
{
"_id" : ObjectId("5f45447285f9b3e4cb8739ad"),
"published": true,
"hidden": false,
"title": "Fantastic Beasts and Where to Find Them"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},
{
"_id" : ObjectId("5f45449fc121a20afa4fbb96"),
"published": false,
"hidden": false,
"title": "Universal Parks & Resorts"
"libraryId": ObjectId("5f45440ee89590218e83a697")
},
{
"_id" : ObjectId("5f4544a5f13839bbe89edb23"),
"published": false,
"hidden": true,
"title": "Ministry of Dawn"
"libraryId": ObjectId("5f45440ee89590218e83a697")
}
根据用户的上下文,我必须 return 可以根据 startsWith()
或 like()
原则过滤不同数量的书籍。
假设我有4本已出版的书,一本是普通用户添加的,一本是隐藏的。
- 管理员应该知道所有这些,因此他会将
booksCount
视为6
。 - 普通用户只能看到自己发布或添加的内容,因此他会看到
booksCount
为5
。 - 以后可能还有一些其他条件。
我想出了这样的聚合:
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, lookupOperation, unwindOperation, group);
mongoTemplate.aggregate(aggregation, "libraries", Document.class).getRawResults().get("results");
一切正常,而不是 count()
操作。
- 如果书籍数组大小为 0,它总是 returns 1.
- 如果书籍数组大小大于 0,则 return 是合适的数量。
- 我试过使用
newBuilder(GroupOps.SUM, null, 0)
而不是count()
,但现在总是 return 0. - 如果我使用
newBuilder(GroupOps.SUM, null, 2)
它 returnssize + 2
。不知道怎么回事
我的问题:
- 谁能告诉我我做错了什么以及如何改正?
- 此外,我需要将“booksCount”从
Integer
解析为String
。小组赛有可能吗?
提前致谢。
它的发生是因为 Aggregation.unwind("books", true);
。当没有连接时,除非你把它做成Aggregation.unwind("books")
,否则这条语句会保留为文档。默认行为是 false
。那么当你计数的时候,这个文件就被算作一个文件。这就是它为您提供 1
作为输出的原因。 Example with wrong output
所以你可以做的是,你可以在下一阶段计算大小。
project("_id", "published", "title", "books")
.and(ArrayOperators.Size.lengthOfArray(ConditionalOperators.ifNull("books").then(Collections.emptyList()))).as("booksCount")