如何根据数组元素的索引对文档进行分组?

Dan*_*iel 6 mapreduce mongodb mongodb-query aggregation-framework

我正在寻找一种获取此类数据的方法

{ "_id" : 5, "count" : 1, "arr" : [ "aga", "dd", "a" ] },
{ "_id" : 6, "count" : 4, "arr" : [ "aga", "ysdf" ] },
{ "_id" : 7, "count" : 4, "arr" : [ "sad", "aga" ] }
Run Code Online (Sandbox Code Playgroud)

我想根据 arr 的第一项(索引)对计数进行求和。在另一个聚合中,我想对 arr 数组中的第一个和第二个项目执行相同的操作。

我尝试过使用 unwind,但这会破坏数据,然后层次结构就会丢失。

我也尝试过使用

$group: {
    _id: {
        arr_0:'$arr.0'
    },
    total:{
        $sum: '$count'
    }
}
Run Code Online (Sandbox Code Playgroud)

但结果是空白数组

sty*_*ane 4

实际上,您不能使用点符号按指定索引处的元素对文档进行分组。对于两个你有两个选择:

$arrayElemAt首先是MongoDB 3.2 中使用 new 运算符的最佳方式。返回数组中指定索引处的元素。

db.collection.aggregate([
    { "$group": {
        "_id": { "$arrayElemAt": [ "$arr", 0 ] }, 
        "count": { "$sum": 1 }
    }}
])
Run Code Online (Sandbox Code Playgroud)

从 MongoDB 3.0 版本开始,您将需要在第一次时对数组进行反规范化,并使用$group运算符返回数组中的第一项。从那里,您将需要使用该值重新组合文档并使用来获取总和。但这仅适用于第一个和最后一个索引,因为 MongoDB 也提供了运算符。_id$first$sum$last

db.collection.aggregate([
    { "$unwind": "$arr" }, 
    { "$group": { 
        "_id": "$_id", 
        "arr": { "$first":  "$arr" }
    }}, 
    { "$group": {
        "_id": "$arr", 
        "count": { "$sum": 1 }
    }}
])
Run Code Online (Sandbox Code Playgroud)

会产生这样的结果:

{ "_id" : "sad", "count" : 1 }
{ "_id" : "aga", "count" : 2 }
Run Code Online (Sandbox Code Playgroud)

p要使用数组中某个位置的元素进行分组,您将有更好的机会使用该mapReduce函数。

var mapFunction = function(){ emit(this.arr[0], 1); };
var reduceFunction = function(key, value) { return Array.sum(value); };
db.collection.mapReduce(mapFunction, reduceFunction, { "out": { "inline": 1 } } )
Run Code Online (Sandbox Code Playgroud)

返回:

{
        "results" : [
                {
                        "_id" : "aga",
                        "value" : 2
                },
                {
                        "_id" : "sad",
                        "value" : 1
                }
        ],
        "timeMillis" : 27,
        "counts" : {
                "input" : 3,
                "emit" : 3,
                "reduce" : 1,
                "output" : 2
        },
        "ok" : 1
}
Run Code Online (Sandbox Code Playgroud)