Spring Boot Mongo DB 查找聚合操作
Posted
技术标签:
【中文标题】Spring Boot Mongo DB 查找聚合操作【英文标题】:Spring Boot Mongo DB Lookup AggregationOperation 【发布时间】:2021-10-02 11:39:07 【问题描述】:首先我想说的是我刚接触 MongoDB,尤其是 MongoData with Springs。我有以下收藏
类别
@Data
@Document(collection = "categories")
public class Category
@Id
private ObjectId id;
@CreatedBy
private ObjectId creatorId;
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime modifiedAt;
@LastModifiedBy
private ObjectId modifiedBy;
private String title;
private String notes;
private boolean enabled = true;
活动
@Data
@Document(collection = "activities")
public class Activity
@Id
private ObjectId id;
@CreatedBy
private ObjectId creatorId;
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime modifiedAt;
@LastModifiedBy
private ObjectId modifiedBy;
private ObjectId budgetId;
private ObjectId categoryId;
private String title;
private String notes;
private Double estimatedBudget;
private boolean enabled;
private boolean recurring;
我想出了一个简单的查询,它将两个集合连接起来,这符合我的预期,如下所示(......也可能不是超级酷的查询)。这个想法是我想根据 categoryId 将所有活动分组在 Category 内。然后,我只想检索具有给定budgetId 的活动。 我应该能够检索所有类别,无论其中是否存在活动,例如 SQL 中的 LEFT JOIN
db.categories.aggregate([
$lookup:
from: "activities",
localField : "_id",
foreignField: "categoryId",
pipeline: [
$match: $and:["budgetId": ObjectId("60f8ef1ed7056b730cdce1db") ]
],
as: "activities"
,
,
$match:
$and:["enabled": true]
])
这以某种方式起作用。 那么问题是如何将上述查询转换为 Springs 中的 AggregationOperation?
我有以下内容,但它排除了其中没有活动的类别。
List<AggregationOperation> operations = new ArrayList<>();
Criteria criteria = Criteria.where("enabled").is(true);
operations.add(match(criteria));
Criteria forBudgetActivitiesCriteria = Criteria.where("activities.budgetId").is(budgetId);
operations.add(lookup("activities", "_id", "categoryId", "activities"));
operations.add(match(forBudgetActivitiesCriteria));
TypedAggregation<Category> aggregation = newAggregation(Category.class, operations);
AggregationResults<Category> results = mongoTemplate.aggregate(aggregation, Category.class);
我猜问题出在这里
Criteria.where("activities.budgetId").is(budgetId);
帮助。并提前致谢。
【问题讨论】:
mongoplayground.net/p/wx7V-uCqFnA 是否达到了您的预期输出?如果是这样,我可以帮你在 Spring boot 中翻译 拥有$match
阶段之前 $lookup
将是构建查询的适当(有效且正确)方式(假设该字段来自categories
集合)。
@prasad_ 当我在 $lookup 之前使用 $match 时,我最终得到一个空结果
@varman 是的,谢谢。我只删除了 $eq: [ "$enabled", true ] 因为我只想在类别上运行匹配,没有活动。如果您能帮忙翻译,我将不胜感激
【参考方案1】:
聚合是
db.categories.aggregate([
$lookup:
from: "activities",
let: "cId": "$_id" ,
pipeline: [
$match:
$expr:
$and: [
$eq: [ "$budgetId", "abc" ] ,
$eq: [ "$$cId", "$categoryId" ] ,
$eq: [ "$enabled", true ]
]
],
as: "join_activities"
,
])
工作Mongo playground
mongodb中有两个$lookup
s。一种是spring数据支持的标准查找(LookupOperation类),第二种是相关子查询查找。不幸的是弹簧数据不支持它。但是有一个Trick to convert
我们可以把它写成 Bson 对象
@Autowired
private MongoTemplate mongoTemplate;
public List<YOUR_CONVERTER_CLASS> test(String value)
Aggregation aggregation = Aggregation.newAggregation(
l-> new Document("$lookup",
new Document("from","activities")
.append("let",new Document("cId","$_id"))
.append("pipeline",
Arrays.asList(
new Document("$match",
new Document("$expr",
new Document(
"$and",
Arrays.asList(
new Document("$eq",Arrays.asList("$budgetId","abc"))
.append("$eq",Arrays.asList("$$cId","$categoryId"))
.append("$eq",Arrays.asList("$enabled",true))
)
)
)
)
)
).append("as","join_activities")
)
).withOptions(AggregationOptions.builder().allowDiskUse(Boolean.TRUE).build());
return mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(YOUR_COLLECTION_CLASS.class), YOUR_CONVERTER_CLASS.class).getMappedResults();
注意:这未经测试,而是基于工作的 mongo 游乐场编写的。 Mongodb 5.0 与您在帖子中发布的签名相同。如果你需要转换你的查询,你可以使用技巧和转换,它只是一个键值对
【讨论】:
谢谢@varman,我不知道键值对转换。它帮助我轻松解决了大部分问题 如果有帮助,请查看meta.stackexchange.com/questions/5234/…以上是关于Spring Boot Mongo DB 查找聚合操作的主要内容,如果未能解决你的问题,请参考以下文章
在 Spring Boot 应用程序中将 mongo db 升级到 3.2
如何在 Spring Boot 中将 mongo db update 运算符应用为 $inc
从 MongoDB 聚合到 Spring Boot 聚合框架
MongoDB + SpringBoot 的基础CRUD聚合查询