获取查询的唯一值的数量

时间:2014-06-30 11:17:47

标签: node.js mongodb

我有一些文件具有以下结构:

{
    "_id": "53ad76d70ddd13e015c0aed1",
    "action": "login",
    "actor": {
        "name": "John",
        "id": 21337037
    }
}

如何在Node.js中进行查询,该查询将返回已执行特定操作的唯一actor的数量。例如,如果我有一个活动流日志,它显示了演员完成的所有操作,并且演员可以多次进行特定操作,那么我如何获得已完成“登录”操作的所有独特演员的数量。演员由actor.id识别

3 个答案:

答案 0 :(得分:2)

db.collection.distinct()

db.collection.distinct("actor.id", { action: "login"})

将返回所有独特的occiriences,然后您可以获得结果集的计数。

PS 不要忘记db.collection.ensureIndex({action: 1})

答案 1 :(得分:1)

您可以使用聚合框架:

db.coll.aggregate([
    /* Filter only actions you're looking for */
    { $match : { action : "login" }},
    /* finally group the documents by actors to calculate the num. of actions */
    { $group : { _id : "$actor", numActions: { $sum : 1 }}}
]);

此查询将按整个actor子文档对文档进行分组,并使用$ sum计算操作数。 $match运算符将仅过滤具有特定操作的文档。

但是,只有当您的actor子文档相同时,该查询才有效。你说过你是id字段识别你的演员。因此,如果由于某种原因,演员子文档不完全相同,那么您的结果就会出现问题。

考虑这三个文件:

{
    ...
    "actor": {
        "name": "John",
        "id": 21337037
    }
},
{
    ...
    "actor": {
        "name": "john",
        "id": 21337037
    }
},
{
    ...
    "actor": {
        "surname" : "Nash",
        "name": "John",
        "id": 21337037           
    }
}

即使id字段相同,它们也会分为三个不同的组。 要解决此问题,您需要按actor.id分组。

db.coll.aggregate([
    /* Filter only actions you're looking for */
    { $match : { action : "login" }},
    /* finally group the documents to calculate the num. of actions */
    { $group : { _id : "$actor.id", numActions: { $sum : 1 }}}
]);

此查询将仅通过查看actor.id字段来正确分组您的文档。

修改

您没有指定使用的驱动程序,因此我编写了MongoDB shell的示例。

与Node.js驱动程序的聚合非常相似,但有一点不同:Node.js是异步的。聚合的结果在回调中返回。您可以查看Node.js aggregation documentation以获取更多示例:

所以Node.js中的聚合命令如下所示:

var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {
    if(err) throw err;

    var collection = db.collection('auditlogs');

    collection.aggregate([ 
        { $match : { action : "login" }}, 
        { $group : { _id : "$actor.id", numActions: { $sum : 1 }}} ],
        function(err, docs) {
            if (err) console.error(err);
            console.log(docs);
            // do something with results
        }
    ); 
});

对于这些测试文件:

{
    "_id" : ObjectId("53b162ea698171cc1677fab8"),
    "action" : "login",
    "actor" : {
        "name" : "John",
        "id" : 21337037
    }
},
{
    "_id" : ObjectId("53b162ee698171cc1677fab9"),
    "action" : "login",
    "actor" : {
        "name" : "john",
        "id" : 21337037
    }
},
{
    "_id" : ObjectId("53b162f7698171cc1677faba"),
    "action" : "login",
    "actor" : {
        "name" : "john",
        "surname" : "nash",
        "id" : 21337037
    }
},
{
    "_id" : ObjectId("53b16319698171cc1677fabb"),
    "action" : "login",
    "actor" : {
        "name" : "foo",
        "id" : 10000
    }
}

它将返回以下结果:

[ { _id: 10000, numActions: 1 },
  { _id: 21337037, numActions: 3 } ]

答案 2 :(得分:0)

aggregation framework是您的答案:

db.actors.aggregate([
    // If you really need to filter
    { "$match": { "action": "login" } },
    // Then group
    { "$group": {
        "_id": {
            "action": "$action",
            "actor": "$actor"
        },
        "count": { "$sum": 1 }
    }}
])

你的“演员”组合是“独一无二的”,所以你需要做的就是在$group管道阶段的_id值下有共同的“分组键”并计算那些“不同”与$sum的组合。