我是MongoDB的新手,在完成任务时需要帮助:
我正在使用MongoDB来查询一个人所采取的行动。这些操作嵌入在人员文档中,如下所示:
{
"_id" : ObjectId("56447ac0583d4871570041c3"),
"email" : "email@example.net",
"actions" : [
{
"name" : "support",
"created_at" : ISODate("2015-10-17T01:40:35.000Z"),
},
{
"name" : "hide",
"created_at" : ISODate("2015-10-16T01:40:35.000Z")
},
{
"name" : "support",
"created_at" : ISODate("2015-10-17T03:40:35.000Z"),
}
]
}
一个人可以使用不同的操作名称执行多项操作(support
和hide
仅为2个示例。)
我知道我可以找到所有至少有support
次行动的人:
db.test.find({'actions.name':'support'})
我想做的是,检索所有至少有X support
次行动的人。这可能不使用JavaScript语法吗?由于人们可能有数百个行动,这将是缓慢的。
所以,如果我希望所有人至少有2 support
个动作,我知道的唯一方法是使用js语法:
db.test.find({$where: function() {
return this.actions.filter(function(action){
return action.name = 'support';
}).length >= 2;
}});
此查询是否还有其他/更好/更快的可能性?
答案 0 :(得分:2)
最好的方法是使用.aggregate()
方法来访问聚合管道。
您可以使用$match
运算符缩小要在管道上处理的文档的大小,以过滤掉与给定条件不匹配的所有文档。
您需要使用$redact
运算符仅返回名称为"支持"的元素数量的文档。在您的数组中$gte
2
。 $map
运算符返回一个与您的critera匹配的子文档数组,并返回false,您可以使用$setDifference
运算符轻松删除它们。当然$size
运算符返回数组的大小。
db.test.aggregate([
{ "$match": {
"actions.name": "support",
"actions.2": { "$exists": true }
}},
{ "$redact": {
"$cond": [
{ "$gte": [
{ "$size": {
"$setDifference": [
{ "$map": {
"input": "$actions",
"as": "action",
"in": {
"$cond": [
{ "$eq": [ "$$action.name", "support" ] },
"$$action",
false
]
}
}},
[false]
]
}},
2
]},
"$$KEEP",
"$$PRUNE"
]
}}
])
从MongoDB 3.2可以使用$filter
运算符来处理。
db.test.aggregate([
{ "$match": {
"actions.name": "support",
"actions.2": { "$exists": true }
}},
{ "$redact": {
"$cond": [
{ "$gte": [
{ "$size": {
"$filter": {
"input": "$actions",
"as": "action",
"cond": { "$eq": [ "$$action.name", "support" ] }
}
}},
2
]},
"$$KEEP",
"$$PRUNE"
]
}}
])
@BlakesSeven指出:
只要被过滤的数据是"唯一的",
$setDifference
就可以了。在这种情况下,它应该""没问题,但是如果任何两个结果包含相同的日期,那么通过将两个结果视为一个结果会使结果偏斜。$filter
是更好的选择,但如果数据不是唯一的,那么现在就需要放松。
答案 1 :(得分:-2)
我没有根据您的尝试对此进行基准测试,但这听起来像是Mongo聚合框架的一个很好的用例。
db.test.aggregate([
{$unwind: "$actions"},
{$group: {
_id: { _id: "$_id", action: "$actions},
count: {$sum: 1}
},
{$match: {$and: [{count: {$gt: 2}}, {"_id.action": "support"]}
]);
请注意,我没有在mongo中运行它,因此它可能有一些语法问题。
背后的想法是:
unwind
actions数组,使数组的每个元素成为自己的文档group
由_id - 动作类型对生成的集合,并计算每个集合的数量。match
将仅过滤我们感兴趣的内容。