我有一些文件具有以下结构:
{
"_id": "53ad76d70ddd13e015c0aed1",
"action": "login",
"actor": {
"name": "John",
"id": 21337037
}
}
如何在Node.js中进行查询,该查询将返回已执行特定操作的唯一actor的数量。例如,如果我有一个活动流日志,它显示了演员完成的所有操作,并且演员可以多次进行特定操作,那么我如何获得已完成“登录”操作的所有独特演员的数量。演员由actor.id识别
答案 0 :(得分:2)
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
的组合。