带有条件的 mongotemplate 聚合 [英] mongotemplate aggregation with condition

查看:42
本文介绍了带有条件的 mongotemplate 聚合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个文档看起来像这样的集合:

I have a collection where the documents look like this:

{
  _id: "545b9fa0dd5318a4285f7ce7",
  owner: "admin",  
  messages: [
    {
      id: "100",
      status: "sent",
      note: ""
    },
    {
      id: "100",
      status: "pending",
      note: ""
    },
    {
      id: "101",
      status: "sent",
      note: ""
    },
    {
      id: "102",
      status: "sent",
      note: ""
    },
    {
      id: "101",
      status: "done",
      note: ""
    }
  ]
}

(这只是一个简短的例子,在我的例子中子数组非常大)

(This is just a short example, in my case the sub array is very large)

我需要查询集合并获取特定文档的一些统计信息.所以在这个例子中,如果我查询具有 id 的文件:545b9fa0dd5318a4285f7ce7"我应该得到这个结果:

I need to query the collection and get some statistics for a specific document. So in this example if I query the doucment that has id: "545b9fa0dd5318a4285f7ce7" I should get this result:

{
   sent: 3,
   pending: 1,
   done: 1
}

如何使用 spring mongotemplate 进行这种聚合?

How can I do such aggregation with spring mongotemplate ?

推荐答案

要做这种事情你需要 $cond 聚合框架中的运算符.Spring Data MongoDB 还没有做到这一点,还有很多东西是常见的$group 操作,甚至仅在 $project.

To do this sort of thing you need the $cond operator in the aggregation framework. Spring Data MongoDB does not do that yet, and there are many things lacking from common $group operations that are even only implemented under $project.

跟踪任何$cond的实现的问题 支持在这里:

The issue for tracking implementation of any $cond support is here:

https://jira.spring.io/browse/DATAMONGO-861

对于世界其他地方,它看起来像这样:

For the rest of the world it looks like this:

db.collection.aggregate([
    { "$match": { "_id": ObjectId("545b9fa0dd5318a4285f7ce7") } },
    { "$unwind": "$messages" },
    { "$group": {
        "_id": "$_id",
        "sent": {
            "$sum": {
                "$cond": [
                    { "$eq": [ "$mesages.status", "sent" ] },
                    1,
                    0
                ]
            }
        },
        "pending": {
            "$sum": {
                "$cond": [
                    { "$eq": [ "$messages.status", "pending" ] },
                    1,
                    0
                ]
            }
        },
        "done": {
            "$sum": {
                "$cond": [
                    { "$eq": [ "$messages.status", "done" ] },
                    1,
                    0
                ]
            }
        }
    }}
])

为了让这种事情在 mongotemplate 聚合下工作,您需要一个扩展聚合操作的类,该类可以从 DBObject 构建:

To get that sort of thing to work under a mongotemplate aggregation you need a class extending aggregation operations that can be built from a DBObject:

public class CustomGroupOperation implements AggregationOperation {
    private DBObject operation;

    public CustomGroupOperation (DBObject operation) {
        this.operation = operation;
    }

    @Override
    public DBObject toDBObject(AggregationOperationContext context) {
        return context.getMappedObject(operation);
    }
}

然后你可以将$group"定义为一个DBObject并在聚合管道中实现:

Then you can define the "$group" as a DBObject and implement in the aggregation pipeline:

   DBObject myGroup = (DBObject)new BasicDBObject(
        "$group", new BasicDBObject(
            "_id","$_id"
        ).append(
            "sent", new BasicDBObject(
                "$sum", new BasicDBObject(
                    "$cond", new Object[]{
                        new BasicDBObject(
                            "$eq", new Object[]{ "$messages.status", "sent"}
                        ),
                        1,
                        0
                    }
                )
            )
        ).append(
            "pending", new BasicDBObject(
                "$sum", new BasicDBObject(
                    "$cond", new Object[]{
                        new BasicDBObject(
                            "$eq", new Object[]{ "$messages.status", "pending"}
                        ),
                        1,
                        0
                    }
                )
             )
        ).append(
            "done", new BasicDBObject(
                "$sum", new BasicDBObject(
                    "$cond", new Object[]{
                         new BasicDBObject(
                            "$eq", new Object[]{ "$messages.status", "done"}
                         ),
                         1,
                         0
                    }
                 )
            )
        )
     );


   ObjectId myId = new ObjectId("545b9fa0dd5318a4285f7ce7");

   Aggregation aggregation = newAggregation(
           match(Criteria.where("_id").is(myId)),
           unwind("messges"),
           new CustomGroupOperation(myGroup)
   );

这允许你想出一个与上面的 shell 表示基本相同的管道.

That allows you to come up with a pipeline that is basically the same as the shell representation above.

所以现在看来​​,在不支持某些操作和序列的情况下,最好的情况是在 AggregationOperation 接口,可以提供 DBObject 或从您自己的自定义方法内部构造一个.

So it would seem that for now, where certain operations and sequences are not supported the best case is to implement a class on the AgggregationOperation interface that can be fed a DBObject or otherwise internally construct one from your own custom methods.

这篇关于带有条件的 mongotemplate 聚合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆