2014-05-24 218 views
1

我試圖分頁我的搜索結果中的MongoDB下面分頁搜索結果

{ 
"data": [ 
{ 
    "_id": "538037b869a1ca1c1ffc96e3", 
    "jobs": "america movie" 
}, 
{ 
    "_id": "538037a169a1ca1c1ffc96e0", 
    "jobs": "superman movie" 
}, 
{ 
    "_id": "538037a769a1ca1c1ffc96e1", 
    "jobs": "spider man movie" 
}, 
{ 
    "_id": "538037af69a1ca1c1ffc96e2", 
    "jobs": "iron man movie" 
}, 
{ 
    "_id": "538037c569a1ca1c1ffc96e4", 
    "jobs": "social network movie" 
} 
], 
"Total_results": 5, 
"author": "Solomon David" 
} 

其作爲被索引和排序由textScore所以我實現分頁這樣的下面

app.get('/search/:q/limit/:lim/skip/:skip',function(req,res){ 

var l = parseInt(req.params.lim); 
var s = parseInt(req.params.skip); 
db.jobs.aggregate({$match:{$text:{$search:req.params.q}}}, 
{$sort:{score:{$meta:"textScore"}}},{$skip:s},{$limit:l},function(err,docs){res.send({data:docs,Total_results:docs.length,author:"Solomon David"});}); 

}); 

但是當我嘗試像這樣localhost:3000/search/movie/limit/1/skip/0 我將我的結果限制爲1並跳過沒有一個,所以我必須得到如下結果。

{ 
    "data": [ 
    { 
     "_id": "538037b869a1ca1c1ffc96e3", 
     "jobs": "america movie" 
    } 
]} 

但我得到這樣

{ 
    "data": [ 
    { 
     "_id": "538037a169a1ca1c1ffc96e0", 
     "jobs": "superman movie" 
    } 
    ], 
    "Total_results": 1, 
    "author": "Solomon David" 
} 

請幫我我在做什麼錯誤

+0

究竟是什麼問題?你得到的領域或結果的順序? –

+0

@NeilLunn如果我限制1,並且跳過,我不得不找工作:美國電影,但我正在找工作:超人電影。檢查我上面列出的搜索結果文檔。 –

+0

所以我不能做聚合分頁?但是當我試圖找到它不工作顯示錯誤?我會用find來替換聚合嗎? –

回答

2

似乎有是幾件事情要在這裏解釋一下,所以我會試着依次穿過它們。但要解決的第一件事是您正在呈現的文檔結構。數組不會產生你想要的結果,所以這裏是一個基本的集合結構,稱其爲「電影」現在:

{ 
    "_id" : "538037b869a1ca1c1ffc96e3", 
    "jobs" : "america movie", 
    "author" : "Solomon David" 
} 
{ 
    "_id" : "538037a169a1ca1c1ffc96e0", 
    "jobs" : "superman movie", 
    "author" : "Solomon David" 
} 
{ 
    "_id" : "538037a769a1ca1c1ffc96e1", 
    "jobs" : "spider man movie", 
    "author" : "Solomon David" 
} 
{ 
    "_id" : "538037af69a1ca1c1ffc96e2", 
    "jobs" : "iron man movie", 
    "author" : "Solomon David" 
} 
{ 
    "_id" : "538037c569a1ca1c1ffc96e4", 
    "jobs" : "social network movie", 
    "author" : "Solomon David" 
} 

因此,有所有單獨的文件的項目,每一個與它的自己的細節和「作者」鍵。現在讓我們考慮基本的文本檢索語句,依然採用聚合:

db.movies.aggregate([ 
    { "$match": { 
     "$text": { 
      "$search": "movie" 
     } 
    }}, 
    { "$sort": { "score": { "$meta": "textScore" } } } 
]) 

這將搜索提供術語創建的「文本」指數和返回由「textScore」從查詢排名結果。這裏使用的形式對於這些階段,你可能會使用到真正看到「分數」值簡寫:

{ "$project": { 
     "jobs": 1, 
     "author": 1, 
     "score": { "$meta": "textScore" } 
    }}, 
    { "$sort": { "score": 1 }} 

但在樣品產生的結果將是這樣的:

{ 
    "_id" : "538037a169a1ca1c1ffc96e0", 
    "jobs" : "superman movie", 
    "author" : "Solomon David" 
} 
{ 
    "_id" : "538037b869a1ca1c1ffc96e3", 
    "jobs" : "america movie", 
    "author" : "Solomon David" 
} 
{ 
    "_id" : "538037c569a1ca1c1ffc96e4", 
    "jobs" : "social network movie", 
    "author" : "Solomon David" 
} 
{ 
    "_id" : "538037af69a1ca1c1ffc96e2", 
    "jobs" : "iron man movie", 
    "author" : "Solomon David" 
} 
{ 
    "_id" : "538037a769a1ca1c1ffc96e1", 
    "jobs" : "spider man movie", 
    "author" : "Solomon David" 
} 

其實樣樣有具有相同的「textScore」,但這是MongoDB將返回它們的順序。除非您提供其他權重或其他排序字段,否則該訂單不會更改。

這基本上涵蓋了文本搜索的第一部分。文本搜索無法修改訂單或過濾包含在文檔內的數組的內容,所以這就是文檔分離的原因。

分頁這些結果是一個簡單的過程,即使$skip$limit是不是最有效的方法去,但一般使用「文本搜索」,當你不會有太大的其他選項。

你似乎試圖達到的效果雖然在某種程度上產生了一些關於你的搜索結果的「統計」。無論如何,用數組存儲文件並不是解決這個問題的方法。所以看的第一件事情是一個綜合聚集例如:

db.movies.aggregate([ 
    { "$match": { 
     "$text": { 
      "$search": "movie" 
     } 
    }}, 
    { "$sort": { "score": { "$meta": "textScore" } } }, 
    { "$group": { 
     "_id": null, 
     "data": { 
      "$push": { 
       "_id": "$_id", 
       "jobs": "$jobs", 
       "author": "$author" 
      } 
     }, 
     "Total_Results": { "$sum": 1 }, 
     "author": { 
      "$push": "$author" 
     } 
    }}, 
    { "$unwind": "$author" }, 
    { "$group": { 
     "_id": "$author", 
     "data": { "$first": "$data" }, 
     "Total_Results": { "$first": "$Total_Results" }, 
     "authorCount": { "$sum": 1 } 
    }}, 
    { "$group": { 
     "_id": null, 
     "data": { "$first": "$data" }, 
     "Total_Results": { "$first": "$Total_Results" }, 
     "Author_Info": { 
      "$push": { 
       "author": "$_id", 
       "count": "$authorCount" 
      } 
     } 
    }},   
    { "$unwind": "$data" }, 
    { "$skip": 0 }, 
    { "$limit": 2 }, 
    { "$group": { 
     "_id": null, 
     "data": { "$push": "$data" }, 
     "Total_Results": { "$first": "$Total_Results" }, 
     "Author_Info": { "$first": "$Author_Info" } 
    }} 
]) 

你在這裏看到許多階段什麼是你所得到的「TOTAL_RESULTS項」和「Author_Info」一些關於你的總搜索結果「統計」以及使用$skip$limit選擇「頁」兩個條目的返回:

{ 
    "_id" : null, 
    "data" : [ 
      { 
        "_id" : "538037a169a1ca1c1ffc96e0", 
        "jobs" : "superman movie", 
        "author" : "Solomon David" 
      }, 
      { 
        "_id" : "538037b869a1ca1c1ffc96e3", 
        "jobs" : "america movie", 
        "author" : "Solomon David" 
      } 
    ], 
    "Total_Results" : 5, 
    "Author_Info" : [ 
      { 
        "author" : "Solomon David", 
        "count" : 5 
      } 
    ] 
} 

這裏的問題是,你可以看到這會變得非常不現實的,當你有一個大的結果集。這裏的關鍵部分是,爲了獲得這些「統計」,您需要使用$group$push將所有結果轉換爲單個文檔的數組。對於幾百個或更多的結果,這可能會很好,但是對於成千上萬的性能會有明顯的下降,更不用說內存資源的使用,以及基本上打破單個文檔的16MB BSON限制的可能性。

這樣做聚合中的所有內容並不是最實際的解決方案,如果您確實需要「統計」,那麼您最好的選擇是將其分成兩個查詢。所以首先對「統計」總:

db.movies.aggregate([ 
    { "$match": { 
      "$text": { 
       "$search": "movie" 
      } 
    }}, 
    { "$group": { 
     "_id": "$author", 
     "count": { "$sum": 1 } 
    }}, 
    { "$group": { 
     "_id": null, 
     "Total_Results": { "$sum": "$count" }, 
     "Author_Info": { 
      "$push": { 
       "author": "$_id", 
       "count": "$count" 
      } 
     } 
    }} 
]) 

這基本上只是這一次,我們不存儲「數據」與實際的搜索結果,而不是擔心傳呼,因爲這同樣的事情,是結果的單個記錄只是提供統計數據。它很快就會下降到一個記錄,並且或多或少地停留在那裏,所以這是一個可擴展的解決方案。

也應該很明顯,您不需要爲每個「頁面」執行此操作,只需要使用初始查詢來運行此操作。 「統計」可以很容易地緩存,所以你可以檢索每個「頁面」請求的數據。

現在所要做的就是簡單地運行每頁所需結果的查詢,而不用「統計」,這可以簡單地使用。 find()形式:

db.movies.find(
    { "$text": { "$search": "movie" } }, 
    { "score": { "$meta": "textScore" } } 
).sort({ "score": { "$meta": "textScore" } }).skip(0).limit(2) 

這裏的短教訓是你想從你搜索「統計」,這樣做,在一個單獨的步驟結果的實際尋呼。這對於通用數據庫分頁來說非常普遍,就像「總體結果」的「統計」一樣簡單。

除此之外,其他選項是查看MongoDB外部的全文搜索解決方案。這些功能更不是實施了「在水腳趾」是的MongoDB提供了開箱即用的,也可能會提供超過該$skip$limit爲「分頁」大套的成績更好的性能解決方案,可以提供豐富的。

+0

要命,但我app.get試圖在這裏( '/搜索/ Q /',函數(REQ,RES){ \t \t db.jobs.find( { 「$文」:{ 「$搜索」: 「movie」}}, {「score」:{「$ meta」:「textScore」}},function(err,docs){res.send({data:docs})} ).sort({「score 「:{」$ meta「:」textScore「}})。skip(2).limit(2) \t \t}); –

+0

我的代碼出了什麼問題? –

+0

@bibindavid「sort」,「skip」和「limit」在錯誤的地方,它們在回調之前,因爲它們都是光標修飾符。 –