计算mongo数据库中的字段名称(而不是值)

时间:2013-03-29 18:34:06

标签: mongodb

有没有办法计算mongodb中的字段名称?我有一个mongo文档数据库,其中包含其他嵌入文档。以下是数据可能的示例。

{   
    "incident": "osint181",
    "summary":"Something happened",
    "actor": {
        "internal": {
            "motive": [
                "Financial"
            ],  
         "notes": "", 
        "role": [
            "Malicious"
        ],  
        "variety": [
            "Cashier"
        ]   
        }   
    }   
}   

另一份文件可能如下所示:

{   
    "incident": "osint182",
    "summary":"Something happened",
    "actor": {
        "external": {
            "motive": [
                "Financial"
            ],  
         "notes": "", 
        "role": [
            "Malicious"
        ],  
        "variety": [
            "Hacker"
        ]   
        }   
    }   
}   

如您所见,演员在第二个文档中已从内部更改为外部。我希望能够做的是计算每种类型演员的事件数量。我的第一次尝试看起来像这样:

db.public.aggregate( { $group : { _id : "$actor", count : { $sum : 1 }}} );

但是这给了我整个子文档,并且计数反映了有多少文档完全相同。相反,我希望得到内部计数和外部计数等。是否有一种优雅的方式来做到这一点?如果不优雅,有人可以给我一个肮脏的方式吗?

2 个答案:

答案 0 :(得分:1)

此类问题的最佳选择是使用mongoDB的map-reduce,它允许您遍历mongoDB文档的所有键,并且您可以轻松地添加复杂的逻辑。在此处查看地图缩小示例:http://docs.mongodb.org/manual/applications/map-reduce/

答案 1 :(得分:1)

这是我根据Devesh的暗示得出的答案。我创建了一个map函数,它查看actor的值,并使用我定义的isEmptyObject函数检查文档是否为空JSON对象。然后我使用mapReduce来检查集合并检查action字段是否为空。如果对象不是空的,而不是返回键的值,我返回键本身,它将被命名为internal或external,或者其他。

这里的魔力是mapReduce中的范围调用,这使得我的isEmptyObject在mapReduce的范围内。结果写入一个名为temp的集合。在从临时收藏中收集我想要的信息之后,我放弃它。

var isEmptyObject = function(obj) {
    for (var name in obj) {
        return false;
    }   
    return true;
};  

var mapFunction = function() {
    if (isEmptyObject(this.action)) {
        emit("Unknown",1); }
    else { 
        for (var key in this.actor) { emit(key,1); } } };

var reduceFunction = function(inKeys,counter) {
    return Array.sum(counter); };

db.public.mapReduce(mapFunction, reduceFunction, {out:"temp", scope:{isEmptyObject:isEmptyObject}} );

foo = db.temp.aggregate(
    { $sort : { value : -1 }});

db.temp.drop();
printjson(foo)