基本上我正在尝试在模型上实现标签功能。
> db.event.distinct("tags")
[ "bar", "foo", "foobar" ]
执行简单的不同查询会检索所有不同的标记。但是,我将如何获得与特定查询匹配的所有不同标记?比方说,我想让所有标签与foo
匹配,然后期望得到["foo","foobar"]
?
以下查询是我未能达到此目的的尝试:
> db.event.distinct("tags",/foo/)
[ "bar", "foo", "foobar" ]
> db.event.distinct("tags",{tags: {$regex: 'foo'}})
[ "bar", "foo", "foobar" ]
答案 0 :(得分:9)
aggregation framework而不是.distinct()
命令:
db.event.aggregate([
// De-normalize the array content to separate documents
{ "$unwind": "$tags" },
// Filter the de-normalized content to remove non-matches
{ "$match": { "tags": /foo/ } },
// Group the "like" terms as the "key"
{ "$group": {
"_id": "$tags"
}}
])
你可能更喜欢在正则表达式的开头使用“锚点”,你的意思是从字符串的“开始”开始。并且在处理$match
之前也执行此$unwind
:
db.event.aggregate([
// Match the possible documents. Always the best approach
{ "$match": { "tags": /^foo/ } },
// De-normalize the array content to separate documents
{ "$unwind": "$tags" },
// Now "filter" the content to actual matches
{ "$match": { "tags": /^foo/ } },
// Group the "like" terms as the "key"
{ "$group": {
"_id": "$tags"
}}
])
这确保您不会在集合中的每个文档上处理$unwind
,而只会在“过滤”以确保之前处理可能包含“匹配标记”值的文档。
使用可能的匹配来缓解大型数组的真正“复杂”方法需要更多工作,以及MongoDB 2.6或更高版本:
db.event.aggregate([
{ "$match": { "tags": /^foo/ } },
{ "$project": {
"tags": { "$setDifference": [
{ "$map": {
"input": "$tags",
"as": "el",
"in": { "$cond": [
{ "$eq": [
{ "$substr": [ "$$el", 0, 3 ] },
"foo"
]},
"$$el",
false
]}
}},
[false]
]}
}},
{ "$unwind": "$tags" },
{ "$group": { "_id": "$tags" }}
])
所以$map
是一个很好的“在线”数组处理器,但它只能走到这么远。 $setDifference
运算符会否定false
个匹配项,但最终您仍需要处理$unwind
来为剩余的$group
阶段执行不同的值。
这里的优点是数组现在“减少”到只匹配的“tags”元素。当您想要在同一文档中存在“多个不同”值时对事件进行“计数”时,请不要使用此项。但同样,还有其他方法可以解决这个问题。