我正在尝试从节点上的MongoDB获取文档。假设文档具有以下结构:
{ "_id": ObjectId, "title" : String, "tags" : Array<String> }
我想按相关性对它们进行排序 - 所以当我在寻找具有“蓝色”或“黄色”标签的文档时,我希望首先获得带有两个标签的文档。到目前为止,我通过谷歌,试验和错误管理:
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);
});
它工作得很好,我得到了有序ID的集合:
[{"_id":"5371355045002fc820a09566","relevance":2},{"_id":"53712fc6c8fcd124216de6cd","relevance":2},{"_id":"5371302ebd4725dc1b908316","relevance":1}]
现在我要进行另一个查询并询问带有这些ID的文档 - 但这是我的问题:可以在一个查询中完成吗?
答案 0 :(得分:3)
是的,当您实际对_id
进行分组时,您可以始终如此,那么该值基本上等同于整个文档。因此,只需将整个文档存储在_id
字段下。
根据您的MongoDB版本,您有两种方法,在MongoDB 2.6之前的版本中,您必须在初始$project
阶段指定整个文档结构(可选择在{{3}之后)在您实际操作文档之前,在您的管道中通常是一个好主意:
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"
}}
])
当然,在管道的最后,您从_id
字段中提取信息,以便恢复原始结构。这是可选的,但你通常想要那个。
对于MongoDB 2.6及更高版本,管道阶段可以使用一个变量,该变量在管道的那个阶段保存文档的结构,称为$match
,您可以将其作为一种快捷方式访问以上形式如此:
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"
}}
])
请记住,为了恢复文档,您仍然需要指定所有必需的字段。
我会注意到,在这种情况下,如果您使用匹配条件“过滤”文档,并且如前所述,您实际上应该在管道的“头部”使用$$ROOT
语句进行过滤。这是聚合框架可以选择索引以优化查询的唯一位置,它还减少了不符合条件的文档数量(假设并非所有文档都标记为“黄色”或“蓝色”)通过剩余的管道阶段:
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"
}}
])
无论如何,这通常比尝试进行另一个查询更有效,当然这个查询不会按照您的方式维护您的排序顺序。