mongotemplate聚合与条件 [英] mongotemplate aggregation with condition

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

问题描述

我有一个文件如下所示的集合:

  {
_id:545b9fa0dd5318a4285f7ce7,
所有者:admin,
消息:[
{
id:100,
状态:已发送,
注意:
},
{
id:100,
状态:待定,
注:
},
{
id:101,
状态:已发送,
注意:
},
{
id:102,
状态:已发送,
注意:
},
{
id:101,
状态:已完成,
注意:
}
]
}

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



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

  {
发送:3,
待定:1,
完成:1
}

如何使用spring mongotemplate进行此类聚合?

解决方案

要执行此操作你需要的东西 $ cond <聚合框架中的/ code> 运算符。 Spring Data MongoDB还没有这样做,而且常见的 $ group 操作甚至只能在 $ project



跟踪任何 <$的实施问题c $ c> $ cond 支持位于:



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



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

  db.collection.aggregate([
{$匹配:{_ id:ObjectId(545b9fa0dd5318a4285f7ce7)}},
{$ unwind:$ messages},
{$ gr oup:{
_id:$ _id,
已发送:{
$ sum:{
$ cond:[
{$ eq:[$ mesages.status,已发送]},
1,
0
]
}
},
待定:{
$ sum:{
$ cond:[
{$ eq:[$ messages.status,pending]},
1,
0
]
}
},
已完成:{
$ sum:{
$ cond:[
{$ eq:[$ messages.status,done]},
1,
0
]
}
}
}}
])

要获得在mongotemplate聚合下工作的东西你需要一个扩展聚合操作的类可以从DBObject构建:

 公共类CustomGroupOperation实现AggregationOperation {
私有DBObject操作;

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

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

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

  DBObject myGroup =(DBObject )new BasicDBObject(
$ group,new BasicDBObject(
_id,$ _ id
).append(
sent,new BasicDBObject($ b $) b$ sum,新的BasicDBObject(
$ cond,new Object [] {
new BasicDBObject(
$ eq,new Object [] {$ messages.status ,发送}
),
1,
0
}


).append(
pending,new BasicDBObject(
$ sum,new BasicDBObject(
$ cond,new Object [] {
new BasicDBObject(
) $ eq,new Object [] {$ messages.status,pending}
),
1,
0
}


).append(
done,新的BasicDBObject(
$ sum,新的BasicDBObject(
$ cond,new Object [] {
new BasicDBObject(
$ eq,new Object [] {$ messages.status,done}
),
1,
0
}



);


ObjectId myId = new ObjectId(545b9fa0dd5318a4285f7ce7);

聚合聚合= newAggregation(
匹配(Criteria.where(_ id)。is(myId)),
unwind(messges),
new CustomGroupOperation(myGroup)
);

这可以让你想出一个与上面的shell表示基本相同的管道。 / p>

所以现在似乎不支持某些操作和序列,最好的情况是在 AgggregationOperation 可以输入的界面DBObject或以其他方式从您自己的自定义方法内部构造一个。


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)

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
}

How can I do such aggregation with spring mongotemplate ?

解决方案

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.

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
                ]
            }
        }
    }}
])

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);
    }
}

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)
   );

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

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天全站免登陆