Mongodb 在单个结果中组合聚合操作

Mongodb 在单个结果中组合聚合操作,mongodb,mongoose,mongodb-query,aggregation-framework,Mongodb,Mongoose,Mongodb Query,Aggregation Framework,我想合并两个聚合操作。第一个操作返回,例如: { "_id" : "Colors", "count" : 12 } { "_id" : "Animals", "count" : 6 } { "_id" : "Red", "count" : 10 } { "_id" : "Blue", "count" : 9 } { "_id" : "Green", "count" : 9 } { "_id" : "White", "count" : 7 } { "_id" : "Yellow", "count

我想合并两个聚合操作。第一个操作返回,例如:

{ "_id" : "Colors", "count" : 12 }
{ "_id" : "Animals", "count" : 6 }
{ "_id" : "Red", "count" : 10 }
{ "_id" : "Blue", "count" : 9 }
{ "_id" : "Green", "count" : 9 }
{ "_id" : "White", "count" : 7 }
{ "_id" : "Yellow", "count" : 7 }
{ "_id" : "Orange", "count" : 7 }
{ "_id" : "Black", "count" : 5 }
{ "_id" : "Goose", "count" : 4 }
{ "_id" : "Chicken", "count" : 3 }
{ "_id" : "Grey", "count" : 3 }
{ "_id" : "Cat", "count" : 3 }
{ "_id" : "Rabbit", "count" : 3 }
{ "_id" : "Duck", "count" : 3 }
{ "_id" : "Turkey", "count" : 2 }
{ "_id" : "Elephant", "count" : 2 }
{ "_id" : "Shark", "count" : 2 }
{ "_id" : "Fish", "count" : 2 }
{ "_id" : "Tiger", "count" : 2 }
{ "_id" : "Purple", "count" : 1 }
{ "_id" : "Pink", "count" : 1 }
第二个操作返回,例如:

{ "_id" : "Colors", "count" : 12 }
{ "_id" : "Animals", "count" : 6 }
{ "_id" : "Red", "count" : 10 }
{ "_id" : "Blue", "count" : 9 }
{ "_id" : "Green", "count" : 9 }
{ "_id" : "White", "count" : 7 }
{ "_id" : "Yellow", "count" : 7 }
{ "_id" : "Orange", "count" : 7 }
{ "_id" : "Black", "count" : 5 }
{ "_id" : "Goose", "count" : 4 }
{ "_id" : "Chicken", "count" : 3 }
{ "_id" : "Grey", "count" : 3 }
{ "_id" : "Cat", "count" : 3 }
{ "_id" : "Rabbit", "count" : 3 }
{ "_id" : "Duck", "count" : 3 }
{ "_id" : "Turkey", "count" : 2 }
{ "_id" : "Elephant", "count" : 2 }
{ "_id" : "Shark", "count" : 2 }
{ "_id" : "Fish", "count" : 2 }
{ "_id" : "Tiger", "count" : 2 }
{ "_id" : "Purple", "count" : 1 }
{ "_id" : "Pink", "count" : 1 }
如何结合这两个操作来实现以下目标

{ "_id" : "Colors", "count" : 12, "items" :
    [
        { "_id" : "Red", "count" : 10 },
        { "_id" : "Blue", "count" : 9 },
        { "_id" : "Green", "count" : 9 },
        { "_id" : "White", "count" : 7 },
        { "_id" : "Yellow", "count" : 7 },
        { "_id" : "Orange", "count" : 7 },
        { "_id" : "Black", "count" : 5 },
        { "_id" : "Grey", "count" : 3 },
        { "_id" : "Purple", "count" : 1 },
        { "_id" : "Pink", "count" : 1 }
    ]
},
{ "_id" : "Animals", "count" : 6, "items" :
    [
        { "_id" : "Goose", "count" : 4 },
        { "_id" : "Chicken", "count" : 3 },
        { "_id" : "Cat", "count" : 3 },
        { "_id" : "Rabbit", "count" : 3 },
        { "_id" : "Duck", "count" : 3 },
        { "_id" : "Turkey", "count" : 2 },
        { "_id" : "Elephant", "count" : 2 },
        { "_id" : "Shark", "count" : 2 },
        { "_id" : "Fish", "count" : 2 },
        { "_id" : "Tiger", "count" : 2 }
    ]
}
模式

var ListSchema = new Schema({
    created: {
        type: Date,
        default: Date.now
    },
    title: {
        type: String,
        default: '',
        trim: true,
        required: 'Title cannot be blank'
    },
    items: {
        type: Array,
        default: [String],
        trim: true
    },
    creator: {
        type: Schema.ObjectId,
        ref: 'User'
    }
});
操作1

db.lists.aggregate(
      [
        { $group: { _id: "$title", count: { $sum: 1 } } },
        { $sort: { count: -1 } }
      ]
    )
操作2

db.lists.aggregate(
      [
        { $unwind: "$items" },
        { $group: { _id: "$items", count: { $sum: 1 } } },
        { $sort: { count: -1 } }
      ]
    )

这真的取决于你所追求的结果。您询问的内容似乎表明您正在查找结果中的“方面计数”,但稍后我将讨论这一点

因为作为一个基本结果,这种方法没有什么错:

Thing.aggregate(
[
{“$组”:{
“_id”:{
“类型”:“$type”,“名称”:“$name”
},
“计数”:{“$sum”:1}
}},
{“$组”:{
“\u id”:“$\u id.type”,
“count”:{“$sum”:“$count”},
“姓名”:{
“$push”:{“name”:“$\u id.name”,“count”:“$count”}
}
}}
],
功能(错误、结果){
log(JSON.stringify(results,undefined,2));
回调(err);
}
)
这会给你一个这样的结果:

[
{
“_id”:“颜色”,
“计数”:50102,
“姓名”:[
{“名称”:“绿色”,“计数”:9906},
{“姓名”:“黄色”,“计数”:10093},
{“名称”:“红色”,“计数”:10083},
{“名称”:“橙色”,“计数”:9997},
{“名称”:“蓝色”,“计数”:10023}
]
},
{
“_id”:“动物”,
“计数”:49898,
“姓名”:[
{“名字”:“老虎”,“伯爵”:9710},
{“名字”:“狮子”,“伯爵”:10058},
{“姓名”:“大象”,“计数”:10069},
{“名称”:“猴子”,“计数”:9963},
{“姓名”:“熊”,“计数”:10098}
]
}
]
这里最基本的方法是简单地分为两个阶段,其中第一阶段将键组合聚合到最低(最细粒度)分组级别,然后再次处理
$group
,以基本上“相加”最高(最细粒度)分组级别的总数,也因此将较低的结果添加到项目数组中

但这并不像“方面计数”中那样“分离”,所以这样做会变得更复杂,也更疯狂。但首先是一个例子:

Thing.aggregate(
[
{“$组”:{
“_id”:{
“类型”:“$type”,
“名称”:“$name”
},
“计数”:{“$sum”:1}
}},
{“$组”:{
“\u id”:“$\u id.type”,
“count”:{“$sum”:“$count”},
“姓名”:{
“$push”:{“name”:“$\u id.name”,“count”:“$count”}
}
}},
{“$组”:{
“_id”:空,
“类型”:{
“$push”:{
“类型:“$\u id”,“计数”:“$count”
}
},
“名称”:{“$push”:“$names”}
}},
{“$unwind”:“$NAME”},
{“$unwind”:“$NAME”},
{“$组”:{
“_id”:“$types”,
“名称”:{“$push”:“$names”}
}},
{“$project”:{
“_id”:0,
“方面”:{
“类型”:“$\u id”,
“名称”:“$names”,
},
“数据”:{“$literal”:[]}
}}
],
功能(错误、结果){
log(JSON.stringify(结果[0],未定义,2));
回调(err);
}
);
这将产生如下输出:

{
“方面”:{
“类型”:[
{“类型”:“颜色”,“计数”:50102},
{“类型”:“动物”,“计数”:49898}
],
“姓名”:[
{“名称”:“绿色”,“计数”:9906},
{“姓名”:“黄色”,“计数”:10093},
{“名称”:“红色”,“计数”:10083},
{“名称”:“橙色”,“计数”:9997},
{“名称”:“蓝色”,“计数”:10023},
{“名字”:“老虎”,“伯爵”:9710},
{“名字”:“狮子”,“伯爵”:10058},
{“姓名”:“大象”,“计数”:10069},
{“名称”:“猴子”,“计数”:9963},
{“姓名”:“熊”,“计数”:10098}
]
},
“数据”:[]
}
然而,显而易见的是,虽然“可能”,但在管道中产生这种输出格式的那种“杂耍”并不是真正有效的。与第一个示例相比,这里的开销很大,只需简单地将结果拆分为它们自己的数组响应,而不依赖于分组键。这明显变得更加复杂,需要生成更多的“方面”

同样正如输出中所暗示的,人们通常要求的“方面计数”是,除了聚合的方面之外,结果“数据”也包括在响应中(可能是分页的)。因此,进一步的复杂情况在这里应该是显而易见的:

{“$group”:{
“_id”:空,
(...)
这种类型的操作的要求是基本上将每一条数据“填充”到一个对象中。在大多数情况下,当然,在结果中需要实际数据的地方(在本示例中使用100000)采用这种方法变得完全不切实际,几乎肯定会超过BSON文档大小限制16MB

在这种情况下,如果您希望在响应中生成结果和数据的“方面”,那么最好的方法是将每个聚合和输出页面作为单独的查询操作运行,并将输出JSON(或其他格式)“流”回接收客户端

作为一个独立的示例:

var async=require('async'),
mongoose=require('mongoose'),
Schema=mongoose.Schema;
猫鼬mongodb://localhost/things');
风险值数据={
“颜色”:[
“红色”、“蓝色”、“绿色”、“黄色”、“橙色”
],
“动物”:[
“狮子”、“老虎”、“熊”、“大象”、“猴子”
]
},
dataKeys=Object.keys(数据);
var thingSchema=new Sc