如何在MongoDB中获取(或聚合)数组的不同键

Zla*_*tko 5 mongodb aggregation-framework

我试图让MongoDB聚合一个具有不同键值对的数组,而不知道键(只需一个简单的总和即可.)

示例文档:

{data: [{a: 3}, {b: 7}]}
{data: [{a: 5}, {c: 12}, {f: 25}]}
{data: [{f: 1}]}
{data: []}
Run Code Online (Sandbox Code Playgroud)

所以基本上每个doc(或它的数组真的)可以有0个或多个条目,我不知道这些对象的键,但我想对这些键的值求和并求平均值.

现在我只是加载一堆文档并在Node中自己完成,但是我想将这项工作卸载到MongoDB.

我知道我可以先解开那些,但是如何从那里开始呢?如果我不知道密钥,如何汇总/平均/最小/最大值?

Bla*_*ven 5

如果您不知道密钥或无法做出合理的教育猜测,那么您基本上无法继续使用聚合框架.您可以提供"所有密钥"供考虑,但我认为您的实际数据看起来更像是这样的:

{ "data": [{ "film": 10 }, { "televsion": 5 },{ "boardGames": 1 }] }
Run Code Online (Sandbox Code Playgroud)

因此,在这里找出所有"关键名称",然后在聚合语句中抛出它将毫无意义.

但是,对于记录,"这就是为什么你不像这样构建你的数据存储".像"电影"这样的信息不应该用作"关键"名称,因为它是可以在数据库系统中搜索并且最重要的是"索引"的有用"数据".

所以你的数据应该是这样的:

{ 
    "data": [
        { "type": "film", "value": 10 },
        { "type": "televsion", "valule": 5 },
        { "type": "boardGames", "value": 1 }
    ]
}
Run Code Online (Sandbox Code Playgroud)

然后聚合语句很简单,还有很多其他的东西:

db.collection.aggregate([
    { "$unwind": "$data" },
    { "$group": {
        "_id": null,
        "sum": { "$sum": "$data.value" },
        "avg": { "$avg": "$data.value" }
    }}
])
Run Code Online (Sandbox Code Playgroud)

但由于密钥名称在文档中不断变化而且没有统一的结构,因此您需要在服务器上进行JavaScript处理以遍历密钥,而meand mapReduce:

db.collection.mapReduce(
    function() {
        this.data.forEach(function(data) {
            Object.keys(data).forEach(function(key) {
                emit(null,data[key]); // emit the value regardless of key name
            });
        });
    },
    function(key,values) {
        return Array.sum(values);     // Just summing for example
    },
    { "out": { "inline": 1 } }
)
Run Code Online (Sandbox Code Playgroud)

当然,这里的JavaScript执行将比聚合框架可用的本机编码运算符慢得多.

因此,在将数据存储在数据库中时,为什么不将"数据"用作"关键名称"应该是一个很好的教训.聚合框架与标准结构一起工作并且速度快,回归到JavaScript处理更灵活,但成本主要在于速度和其他功能.