【问题标题】:MongoDB sort by relevanceMongoDB 按相关性排序
【发布时间】:2014-05-14 10:00:03
【问题描述】:

我正在尝试从节点上的 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 的文档 - 但这是我的问题:可以在一个查询中完成吗?

【问题讨论】:

  • 您将$$ROOT 投射到将为您提供原始文档的管道中

标签: node.js mongodb aggregation-framework mongojs


【解决方案1】:

是的,当您实际在_id 上进行分组时,您总是可以这样做,那么该值基本上等同于整个文档。因此,只需将整个文档存储在_id 字段下即可。

根据您的 MongoDB 版本,您有几种方法可以解决此问题,在 MongoDB 2.6 之前的版本中,您必须在初始 $project 阶段指定整个文档结构(可以选择在 $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"
    }}
])

当然,在管道结束时,您从_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"
    }}
])

请记住,为了恢复文档,您仍然需要指定所有必填字段。

我会注意到,由于在这种情况下您正在使用匹配条件“过滤”文档,并且如前所述,您实际上应该在管道的“头部”使用 $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"
    }}
])

无论如何,这通常比尝试执行另一个查询更有效,这当然不会以您所做的方式维护您的排序顺序。

【讨论】:

    猜你喜欢
    • 2012-09-28
    • 1970-01-01
    • 2017-06-20
    • 1970-01-01
    • 2011-01-26
    • 2017-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-04
    相关资源
    最近更新 更多