Mongodb在带有正则表达式查询的数组字段上是不同的?

net*_*ain 5 regex mongodb mongodb-query aggregation-framework

基本上我正在尝试在模型上实现标签功能.

> db.event.distinct("tags")
[ "bar", "foo", "foobar" ]
Run Code Online (Sandbox Code Playgroud)

执行简单的不同查询会检索所有不同的标记.但是,我将如何获得与特定查询匹配的所有不同标记?比方说,我想让所有标签匹配foo,然后期望得到["foo","foobar"]结果?

以下查询是我尝试实现此目的的失败尝试:

> db.event.distinct("tags",/foo/)
[ "bar", "foo", "foobar" ]

> db.event.distinct("tags",{tags: {$regex: 'foo'}})
[ "bar", "foo", "foobar" ]
Run Code Online (Sandbox Code Playgroud)

Nei*_*unn 9

聚合框架,而不是.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"
    }}
])
Run Code Online (Sandbox Code Playgroud)

你最好在正则表达式的开头使用"锚点",你的意思是从字符串的"开始"开始.$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"
    }}
])
Run Code Online (Sandbox Code Playgroud)

这样可以确保$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" }}
])
Run Code Online (Sandbox Code Playgroud)

所以这$map是一个很好的"在线"阵列处理器,但它只能到目前为止.该$setDifference运营商否定了false比赛,但最终你还是需要处理$unwind做余下的$group整体不同的值的阶段.

这里的优点是数组现在"减少"到只匹配的"tags"元素.当您想要在同一文档中存在"多个不同"值时对事件进行"计数"时,请不要使用此项.但同样,还有其他方法可以解决这个问题.