今天做了一個mongo的分頁查詢,記錄一下mongo如何同時返回分頁記錄和記錄數的方法,利用的是mongo的聚合查詢里面的$facet階段,具體使用參考官方文檔即可https://docs.mongodb.com/manual/reference/operator/aggregation/facet/
按照官方文檔的說法,
Input documents are passed to the
$facetstage only once.$facetenables various aggregations on the same set of input documents, without needing to retrieve the input documents multiple times.
利用的是同一個上個階段返回的記錄集,所以從原理上來說是沒有二次查詢的,效率自然比傳統數據庫里面的分頁實現方式效率上要高,不過由於aggregate的返回只能是文檔,所以對於結果的處理可能會比較繁瑣,需要自己一個個解析以及類型強轉。
類似的facet階段可以采用如下形式
{
'$facet': {
'count': [
{
'$count': 'count'
}
],
'data': [
{
'$sort': {
'_id': 1
}
}, {
'$skip': 1
}, {
'$limit': 2
}
]
}
}
出來的結果是一個文檔,而且由於mongo的單文檔限制是16M,所以相應的data字段里面的記錄集不能太多,不過既然做分頁了,這個地方應該就不需要考慮了吧.出來的記過類似這個樣子
{
"count": [
{
"count": 14453
}
],
"data": [
{
"ts": "2021-01-21 08:00:28",
"x": "0.0000",
"y": "0.2089"
},
{
"ts": "2021-01-21 08:01:19",
"x": "0.0000",
"y": "0.3256"
}
]
}
最后如果是在java里面的話,最后的結果集可能就需要自己進行額外處理了,類似這個樣子
Object count = ((Document)((List)rs.get(0).get("count")).get(0)).get("count");
Object data = (List)rs.get(0).get("data");
有點不好看.
##補充
如果是在mongo shell 里面的話,對於db.test.find()方法返回的游標cursor,官方文檔里面提供了cursor.count(applySkipLimit),用以忽略skip()和limit()的影響,如果applySkipLimit設置為true的話,就會對相關返回結果應用limit和skip的效應,有興趣的可以自己去研究一下.不知道其他語言的驅動里面有沒有相關的api,在java里面我是沒找到。
