MongoDB查找子文档并对结果进行排序

时间:2014-03-30 23:19:40

标签: mongodb sorting mongodb-query aggregation-framework

我在MongoDB中有一个具有复杂结构和子文档的集合。 该文件的结构如下:

doc1 = {
    '_id': '12345678',
    'url': "http//myurl/...",
    'nlp':{
        "status": "OK",
        "entities": {
            "0": {
                "type" : "Person",
                "relevance": "0.877245",
                "text" : "Neelie Kroes"
            },
            "1": {
                "type": "Company",
                "relevance": "0.36242",
                "text": "ICANN"
            },
            "2": {
                "type": "Company",
                "relevance": "0.265175",
                "text": "IANA" 
            }
        }
    }
}


doc2 = {
    '_id': '987456321',
    'url': "http//myurl2/...",
    'nlp':{
        "status": "OK",
        "entities": {
            "0": {
                "type": "Company",
                "relevance": "0.96",
                "text": "ICANN"
            },
            "1": {
                "type" : "Person",
                "relevance": "0.36242",
                "text" : "Neelie Kroes"
            },
            "2": {
                "type": "Company",
                "relevance": "0.265175",
                "text": "IANA" 
            }
        }
    }
}

我的任务是在子文档中搜索“type”和“text”,然后按“related”排序。 使用$ elemMatch运算符,我可以执行查询:

db.resource.find({
    'nlp.entities': {
        '$elemMatch': {'text': 'Neelie Kroes', 'type': 'Person'}
    }
});

完美,现在我必须按照“人物”类型的实体对所有记录进行排序,并按相关性降序对“Neelie Kroes”进行排序。

我尝试使用正常的“排序”,但是,作为$ {emmM}中关于sort()的manual said,结果可能无法反映排序顺序,因为sort()已应用于元素$ elemMatch投影前的数组。

事实上,_id:987456321将是第一个(相关性为0.96,但引用了ICANN)。

如何根据匹配的子文档的相关性对文档进行排序?

P.S。:我无法更改文档结构。

1 个答案:

答案 0 :(得分:1)

如上所述,我希望您的文档确实有一个数组,但是如果$ elemMatch正在为您工作,那么他们应该。

无论如何,您无法使用find对数组中的元素进行排序。但有一种情况是您可以使用.aggregate()执行此操作:

db.collection.aggregate([

    // Match the documents that you want, containing the array
    { "$match": {
        "nlp.entities": {
            "$elemMatch": { 
                "text": "Neelie Kroes", 
                "type": "Person"   
            }
        }
    }},

    // Project to "store" the whole document for later, duplicating the array
    { "$project": {
        "_id": {
            "_id": "$_id",
            "url": "$url",
            "nlp": "$nlp"          
        },
        "entities": "$nlp.entities"
    }},

    // Unwind the array to de-normalize
    { "$unwind": "$entities" },

    // Match "only" the relevant entities
    { "$match": {
        "entities.text": "Neelie Kroes", 
        "entities.type": "Person"   
    }},

    // Sort on the relevance
    { "$sort": { "entities.relevance": -1 } },

    // Restore the original document form
    { "$project": {
        "_id": "$_id._id",
        "url": "$_id.url",
        "nlp": "$_id.nlp"
    }}
])

基本上,在对包含相关匹配的文档执行$match条件后,您可以使用$project“存储”_id字段中的原始文档和{{3} “实体”数组的“副本”。

下一个$unwind“过滤”数组内容,只过滤那些相关的内容。然后将$match应用于“匹配”文档。

由于“原始”文档存储在_id下,您可以使用$sort来“恢复”文档实际上必须开始的结构。

这就是你对匹配的数组元素进行“排序”的方法。

请注意,如果您在父文档的数组中有多个“匹配”,那么您必须使用额外的$project阶段来获取“$ max”值相关性“字段以完成您的排序。