mongotemplate聚合与条件 [英] mongotemplate aggregation with condition
问题描述
我有一个文件如下所示的集合:
{
_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屋!