m1g*_*u3l 5 mongodb node.js aggregation-framework mongojs
我正在尝试从节点上的 MongoDB 获取文档。假设文档具有以下结构:
{ "_id": ObjectId, "title" : String, "tags" : Array<String> }
Run Code Online (Sandbox Code Playgroud)
我想按相关性对它们进行排序 - 因此,当我寻找带有“蓝色”或“黄色”标签的文档时,我想先获取带有两个标签的文档。到目前为止,我由谷歌管理,反复试验:
var tags = [ "yellow", "blue" ];
db.collection('files').aggregate([
{ $project : { tags: 1 } },
{ $unwind : "$tags" },
{ $match : { "tags": { "$in": tags } } },
{ $group : { _id: "$_id", relevance: { $sum:1 } } },
{ $sort : { relevance : -1 } },
], function(err, success) {
console.log(success);
});
Run Code Online (Sandbox Code Playgroud)
它工作得很好,我得到了排序的 id 集合:
[{"_id":"5371355045002fc820a09566","relevance":2},{"_id":"53712fc6c8fcd124216de6cd","relevance":2},{"_id":"5371302ebd4725dc1b908316","relevance":1}]
Run Code Online (Sandbox Code Playgroud)
现在我将进行另一次查询并要求使用这些 id 的文档 - 但这是我的问题:它可以在一个查询中完成吗?
是的,当您实际分组时,您可以像往常一样,_id那么该值本质上等于整个文档。因此,只需将整个文档存储在该_id字段下即可。
根据您的 MongoDB 版本,您有几种方法可以实现此目的,并且在 MongoDB 2.6 之前的版本中,您必须在管道中的初始$project阶段(可以选择在 a 之后,这通常是一个好主意)指定整个文档结构。$match您实际上操纵了该文档:
var tags = ["yellow","blue"];
db.collection.aggregate([
{ "$project" : {
"_id": {
"_id": "$_id",
"title": "$title",
"tags": "$tags"
},
"tags": 1
}},
{ "$unwind": "$tags" },
{ "$match": { "tags": { "$in": tags } } },
{ "$group": { "_id": "$_id", "relevance": { "$sum":1 } } },
{ "$sort": { "relevance" : -1 } },
{ "$project": {
_id: "$_id._id",
"title": "$_id.title",
"tags": "$_id.tags"
}}
])
Run Code Online (Sandbox Code Playgroud)
当然,在管道的末尾,您从现场提取信息,_id以恢复原始结构。这是可选的,但您通常需要这样做。
对于 MongoDB 2.6 及更高版本,有一个可用于管道阶段的变量,该变量保存管道该阶段的文档结构$$ROOT,您可以将其作为上述形式的快捷方式来访问,如下所示:
var tags = ["yellow","blue"];
db.collection.aggregate([
{ "$project" : {
"_id": "$$ROOT",
"tags": 1
}},
{ "$unwind": "$tags" },
{ "$match": { "tags": { "$in": tags } } },
{ "$group": { "_id": "$_id", "relevance": { "$sum":1 } } },
{ "$sort": { "relevance" : -1 } },
{ "$project": {
"_id": "$_id._id",
"title": "$_id.title",
"tags": "$_id.tags"
}}
])
Run Code Online (Sandbox Code Playgroud)
请记住,为了恢复文档,您仍然需要指定所有必填字段。
我要注意的是,在这种情况下,当您使用匹配条件“过滤”文档时,正如前面提到的,您实际上应该使用$match管道“头部”的语句进行过滤。这是聚合框架可以选择索引以优化查询的唯一地方,并且它还减少了不满足您的条件的文档数量(假设并非所有内容都有标签“黄色”或“蓝色”)经历剩余的管道阶段:
db.collection.aggregate([
{ "$match": { "tags": { "$in": tags } } },
{ "$project" : {
"_id": {
"_id": "$_id",
"title": "$title",
"tags": "$tags"
},
"tags": 1
}},
{ "$unwind": "$tags" },
{ "$match": { "tags": { "$in": tags } } },
{ "$group": { "_id": "$_id", "relevance": { "$sum":1 } } },
{ "$sort": { "relevance" : -1 } },
{ "$project": {
_id: "$_id._id",
"title": "$_id.title",
"tags": "$_id.tags"
}}
])
Run Code Online (Sandbox Code Playgroud)
无论如何,这通常应该比尝试执行另一个查询更有效,这当然不会像您所做的那样维持您的排序顺序。
| 归档时间: |
|
| 查看次数: |
694 次 |
| 最近记录: |