【问题标题】:Spring Boot Mongo DB Lookup AggregationOperationSpring Boot Mongo DB 查找聚合操作
【发布时间】: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 ] } 因为我只想在类别上运行匹配,没有活动。如果您能帮忙翻译,我将不胜感激

标签: mongodb spring-boot mongodb-query aggregation-framework


【解决方案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中有两个$lookups。一种是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 与您在帖子中发布的签名相同。如果你需要转换你的查询,你可以使用技巧和转换,它只是一个键值对

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-30
  • 1970-01-01
  • 1970-01-01
  • 2019-01-06
  • 2017-05-02
  • 1970-01-01
  • 2020-08-26
相关资源
最近更新 更多