2014-03-30 95 views
1

我在MongoDB中擁有一個具有複雜結構和子文檔的集合。 文檔有一個結構是這樣的: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" 
      } 
     } 
    } 
} 

我的任務是「相關性」搜索「類型」和「文本」的子文檔中,然後進行排序。 隨着$ elemMatch操作我能夠執行查詢:

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

完美,現在我已經通過相關下降到所有類型「人」和值「尼利·克羅斯」的實體記錄進行排序。

我嘗試了一個正常的「排序」,但是,作爲關於$ elemMatch中的sort()的manual said,結果可能不會反映排序順序,因爲sort()是在數組之前應用於數組的元素$ elemMatch投影。

事實上,_id:987456321將是第一個(相關度爲0.96,但提及ICANN)。

我該怎麼辦,通過匹配的子文檔的相關性對我的文檔進行排序?

P.S .:我無法更改文檔結構。

+0

這是作爲一個工具的轉儲出來,或者這是你的文件在mongo shell中的實際外觀?我這樣說是因爲你如何表示「實體」是作爲「子文檔」而不是數組。這些不能通過任何標準手段進行分類。 –

回答

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條件包含相關比賽文稿後,然後在_id領域使用$project「店」的原始文件和$unwind「實體」數組的「副本」。

下一個$match將數組內容「過濾」到只有那些相關的數組內容。然後,您將$sort應用於「匹配」文檔。

由於「原始」文檔存儲在_id下,因此您使用$project來「恢復」該文檔實際上必須從頭開始的結構。

這就是你對數組的匹配元素「排序」的方法。

注意如果你父文檔一個陣列中有多個「匹配」,那麼你就必須使用一個額外的$group階段獲得以完成對「相關性」字段中的$最大值您分類。

+0

謝謝你完美的作品。第一次很慢,但之後非常快。集合函數是否存儲在RAM中,緩存還是讓其他加速系統?再次感謝你。 –