Pra*_*tel 0 mapreduce mongodb aggregation-framework
假设我们在数据库中有以下结构的记录。
{
"_id": 1234,
"tags" : [ "t1", "t2", "t3" ]
}
Run Code Online (Sandbox Code Playgroud)
现在,我想检查数据库是否包含带有数组中指定的任何标签的记录 tagsArray which is [ "t3", "t4", "t5" ]
我了解$in运算符,但我不仅想知道数据库中的任何记录是否具有tagsArray中指定的任何标记,还想知道数据库中记录的哪个标记与tagsArray中指定的任何标记相匹配。(即在上述记录中为t3)
也就是说,我想比较两个数组(一个记录,另一个由我给定),并找出公共元素。
我需要将此表达式与查询中的许多表达式一起使用,因此投影运算符(例如$,$ elematch等)不会有太大用处。(或者有没有一种方法可以使用它而不必遍历所有记录?)
我想我可以使用$where运算符,但我认为这不是最好的方法。如何解决这个问题?
有几种方法可以执行所需的操作,这仅取决于您的MongoDB版本。只需提交外壳响应。内容基本上是JSON表示形式,对于Java中的DBObject实体或要在服务器上执行的JavaScript而言,不难翻译,因此实际上不会改变。
第一个也是最快的方法是在MongoDB 2.6和更高版本中,您将获得新的设置操作:
var test = [ "t3", "t4", "t5" ];
db.collection.aggregate([
{ "$match": { "tags": {"$in": test } }},
{ "$project": {
"tagMatch": {
"$setIntersection": [
"$tags",
test
]
},
"sizeMatch": {
"$size": {
"$setIntersection": [
"$tags",
test
]
}
}
}},
{ "$match": { "sizeMatch": { "$gte": 1 } } },
{ "$project": { "tagMatch": 1 } }
])
Run Code Online (Sandbox Code Playgroud)
那里有新的运算符$setIntersection正在执行主要工作,还有$size运算符将测量数组大小并帮助后者进行过滤。这最终是对“集合”的基本比较,以便找到相交的项目。
如果您使用的是MongoDB的早期版本,则仍然可以这样做,但是您需要更多的阶段,这可能会影响性能,具体取决于您是否拥有大型阵列:
var test = [ "t3", "t4", "t5" ];
db.collection.aggregate([
{ "$match": { "tags": {"$in": test } }},
{ "$project": {
"tags": 1,
"match": { "$const": test }
}},
{ "$unwind": "$tags" },
{ "$unwind": "$match" },
{ "$project": {
"tags": 1,
"matched": { "$eq": [ "$tags", "$match" ] }
}},
{ "$match": { "matched": true }},
{ "$group": {
"_id": "$_id",
"tagMatch": { "$push": "$tags" },
"count": { "$sum": 1 }
}}
{ "$match": { "count": { "$gte": 1 } }},
{ "$project": { "tagMatch": 1 }}
])
Run Code Online (Sandbox Code Playgroud)
或者,如果所有这些似乎都涉及到了,或者您的数组足够大以至于造成性能差异,那么总会有mapReduce:
var test = [ "t3", "t4", "t5" ];
db.collection.mapReduce(
function () {
var intersection = this.tags.filter(function(x){
return ( test.indexOf( x ) != -1 );
});
if ( intersection.length > 0 )
emit ( this._id, intersection );
},
function(){},
{
"query": { "tags": { "$in": test } },
"scope": { "test": test },
"output": { "inline": 1 }
}
)
Run Code Online (Sandbox Code Playgroud)
请注意,在所有情况下,$in即使不是完全匹配,操作员仍然可以帮助您减少结果。另一个常见元素是检查相交结果的“大小”以减少响应。
所有这些都很容易编写,如果您还没有获得最佳结果,请说服老板改用MongoDB 2.6或更高版本。