简体   繁体   English

如何在 Spring Data 中进行 Mongo 聚合查询?

[英]How to do a Mongo aggregation query in Spring Data?

It's the first time I am using Mongo in Java and I am having some problems with this aggregation query.这是我第一次在 Java 中使用 Mongo,我在这个聚合查询中遇到了一些问题。 I can do some simple queries in Mongo for Spring with @Query annotation in my Repository interface which extends the MongoRepository<T, ID> .我可以在我的 Repository 接口中使用@Query注释在 Mongo for Spring 中做一些简单的查询,它扩展了MongoRepository<T, ID> It would be helpful to know which approach to take when you do long aggregations in Spring-Data.了解在 Spring-Data 中进行长聚合时采用哪种方法会很有帮助。

db.post.aggregate([
    {
      $match: {}
    },
    {
      $lookup: {
        from: "users",
        localField: "postedBy",
        foreignField: "_id",
        as: "user"
      }
    },
    {
      $group: {
        _id: {
          username: "$user.name",
          title: "$title",
          description: "$description",
          upvotes: { $size: "$upvotesBy" },
          upvotesBy: "$upvotesBy",
          isUpvoted: { $in: [req.query.userId, "$upvotesBy"] },
          isPinned: {
            $cond: {
              if: { $gte: [{ $size: "$upvotesBy" }, 3] },
              then: true,
              else: false
            }
          },
          file: "$file",
          createdAt: {
            $dateToString: {
              format: "%H:%M %d-%m-%Y",
              timezone: "+01",
              date: "$createdAt"
            }
          },
          id: "$_id"
        }
      }
    },
    { $sort: { "_id.isPinned": -1, "_id.createdAt": -1 } }
])

Although this is old thread, but I hope whoever found this thread can now safely for doing multi stage/pipeline aggregation(not quite sure what it's call) in MongoRepository.虽然这是旧线程,但我希望发现这个线程的人现在可以安全地在 MongoRepository 中进行多阶段/管道聚合(不太确定它的名称)。 As I'm also struggling looking for clue and example of aggregation in mongo repository without mongo template.因为我也在努力寻找没有 mongo 模板的 mongo 存储库中聚合的线索和示例。

But now, I'm able to do the Aggregation pipeline as per spring doc said in here但现在,我能够做聚合管道按春文档中说, 在这里

My aggregation looks like this in mongoshell:我的聚合在 mongoshell 中如下所示:

db.getCollection('SalesPo').aggregate([
    {$project: {
        month: {$month: '$poDate'},
        year: {$year: '$poDate'},
        amount: 1,
        poDate: 1
     }},
      {$match: {$and : [{year:2020} , {month:7}] 
     }}
      ,
      {$group: { 
          '_id': {
            month: {$month: '$poDate'},
            year: {$year: '$poDate'} 
          },
          totalPrice: {$sum: {$toDecimal:'$amount'}},
          }
      },
    {$project: {
        _id: 0,
        totalPrice: {$toString: '$totalPrice'}
     }}
 ])

While I transform it into @Aggregation annotation in MongoRepository become like this below (I'm removing the aposthrephe and also replace with method params):当我将它转换为 MongoRepository 中的 @Aggregation 注释时,如下所示(我正在删除撇号并替换为方法参数):

@Repository
public interface SalesPoRepository extends MongoRepository<SalesPo, String> {

@Aggregation(pipeline = {"{$project: {\n" +
        "        month: {$month: $poDate},\n" +
        "        year: {$year: $poDate},\n" +
        "        amount: 1,\n" +
        "        poDate: 1\n" +
        "     }}"
        ,"{$match: {$and : [{year:?0} , {month:?1}] \n" +
        "     }}"
        ,"{$group: { \n" +
        "          '_id': {\n" +
        "            month: {$month: $poDate},\n" +
        "            year: {$year: $poDate} \n" +
        "          },\n" +
        "          totalPrice: {$sum: {$toDecimal:$amount}},\n" +
        "          }\n" +
        "      }"
    ,"{$project: {\n" +
        "        _id: 0,\n" +
        "        totalPrice: {$toString: $totalPrice}\n" +
        "     }}"})
    AggregationResults<SumPrice> sumPriceThisYearMonth(Integer year, Integer month);

My Document looks like this:我的文档如下所示:

@Document(collection = "SalesPo")
@Data
public class SalesPo {
  @Id
  private String id;
  @JsonSerialize(using = LocalDateSerializer.class)
  private LocalDate poDate;
  private BigDecimal amount;
}

And the SumPrice class for hold the projections:以及用于保持预测的 SumPrice 类:

@Data
public class SumPrice {
  private BigDecimal totalPrice;
}

I hope this answer can help whoever try to do aggregation in mongorepository without using mongotemplate.我希望这个答案可以帮助那些尝试在不使用 mongotemplate 的情况下在 mongorepository 中进行聚合的人。

You can implement the AggregationOperation and write the custom aggregation operation query and then use MongoTemplate to execute any mongo shell query you have executed in your mongo shell as below:您可以实现AggregationOperation并编写自定义聚合操作查询,然后使用MongoTemplate执行您在 mongo shell 中执行的任何 mongo shell 查询,如下所示:

Custom Aggregation Operation自定义聚合操作

import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;

public class CustomAggregationOperation implements AggregationOperation {

  private String jsonOperation;

  public CustomAggregationOperation(String jsonOperation) {
    this.jsonOperation = jsonOperation;
  }

  @Override
  public org.bson.Document toDocument(AggregationOperationContext aggregationOperationContext) {
    return aggregationOperationContext.getMappedObject(org.bson.Document.parse(jsonOperation));
  }
}

Any Mongo Shell Aggregation query executor任何 Mongo Shell 聚合查询执行器

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.stereotype.Service;
import sample.data.mongo.models.Course;

@Service
public class LookupAggregation {

  @Autowired
  MongoTemplate mongoTemplate;

  public void LookupAggregationExample() {

    AggregationOperation unwind = Aggregation.unwind("studentIds");

    String query1 = "{$lookup: {from: 'student', let: { stuId: { $toObjectId: '$studentIds' } },"
        + "pipeline: [{$match: {$expr: { $eq: [ '$_id', '$$stuId' ] },},}, "
        + "{$project: {isSendTemplate: 1,openId: 1,stu_name: '$name',stu_id: '$_id',},},], "
        + "as: 'student',}, }";

    TypedAggregation<Course> aggregation = Aggregation.newAggregation(
        Course.class,
        unwind,
        new CustomAggregationOperation(query1)
    );

    AggregationResults<Course> results =
        mongoTemplate.aggregate(aggregation, Course.class);
    System.out.println(results.getMappedResults());
  }
}

For more details, Have a look at the Github repository classes: CustomAggregationOperation & LookupAggregation有关更多详细信息,请查看Github 存储库类: CustomAggregationOperation & LookupAggregation

Other approaches also using MongoTemplate :其他方法也使用MongoTemplate

#1. #1. Define an interface for your custom code for Model Post :为 Model Post 的自定义代码定义一个接口:

interface CustomPostRepository {
     List<Post> yourCustomMethod();
}

#2. #2. Add implementation for this class and follow the naming convention to make sure we can find the class.添加该类的实现并遵循命名约定以确保我们可以找到该类。

class CustomPostRepositoryImpl implements CustomPostRepository {

    @Autowired
    private MongoOperations mongoOperations;

    public List<Post> yourCustomMethod() {

      // custom match queries here
      MatchOperation match = null;
      // Group by , Lookup others stuff goes here
      // For details: https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/aggregation/Aggregation.html

      Aggregation aggregate = Aggregation.newAggregation(match);

      AggregationResults<Post> orderAggregate = mongoOperations.aggregate(aggregate,
                      Post.class, Post.class);
      return orderAggregate.getMappedResults();

    }
}

#3. #3. Now let your base repository interface extend the custom one and the infrastructure will automatically use your custom implementation:现在让您的基本存储库接口扩展自定义接口,基础架构将自动使用您的自定义实现:

interface PostRepository extends CrudRepository<Post, Long>, CustomPostRepository {

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM