速度を上げるために、クエリを10件の結果に制限したいと思います
db.collection.find( ... ).limit(10)
ただ、総数も知りたいので、「124個あったけど10個しかない」と。これを行うための良い効率的な方法はありますか?
デフォルトでは、クエリ全体の結果をcount()
無視しlimit()
てカウントします。したがって、たとえばこれを行う場合、var a = db.collection.find(...).limit(10);
実行a.count()
するとクエリの総数が得られます。
count(1)を実行すると、制限とスキップが含まれます。
@johnnycrabが受け入れた回答は、mongoCLIに対するものです。
Node.jsとExpress.jsで同じコードを記述する必要がある場合、toArrayの「結果」とともに「count」関数を使用できるようにするには、このように使用する必要があります。
var curFind = db.collection('tasks').find({query});
次に、このように2つの関数を実行できます(一方が他方にネストされています)
curFind.count(function (e, count) {
// Use count here
curFind.skip(0).limit(10).toArray(function(err, result) {
// Use result here and count here
});
});
cursor.count()
無視する必要がcursor.skip()
ありcursor.limit()
、デフォルトで。
ソース:http ://docs.mongodb.org/manual/reference/method/cursor.count/#cursor.count
$facet
同じ入力ドキュメントのセットで、単一のステージ内で複数の集計パイプラインを処理するステージを使用できます。
// { item: "a" }
// { item: "b" }
// { item: "c" }
db.collection.aggregate([
{ $facet: {
limit: [{ $limit: 2 }],
total: [{ $count: "count" }]
}},
{ $set: { total: { $first: "$total.count" } } }
])
// { limit: [{ item: "a" }, { item: "b" }], total: 3 }
limit: [{ $limit: 2 }]
このようにして、同じクエリ内で、いくつかのドキュメント( )とドキュメントの総数()の両方を取得できます{ $count: "count" }
。
最終ステージは$set
オプションのクリーンアップステップであり、$count
ステージの結果を投影するためにあります。"total" : [ { "count" : 3 } ]
total: 3
プッシュとスライスを使用した解決策があります:https ://stackoverflow.com/a/39784851/4752635
私は好みます
$$ROOTをプッシュして$sliceを使用するソリューションでは、大規模なコレクションの場合、ドキュメントメモリの制限が16MBになります。また、大規模なコレクションの場合、2つのクエリを一緒にすると、$$ROOTをプッシュするクエリよりも高速に実行されるようです。それらを並行して実行することもできるので、2つのクエリのうち遅い方(おそらくソートするクエリ)によってのみ制限されます。
私は2つのクエリと集約フレームワークを使用してこのソリューションに落ち着きました(注-この例ではnode.jsを使用していますが、考え方は同じです):
var aggregation = [
{
// If you can match fields at the begining, match as many as early as possible.
$match: {...}
},
{
// Projection.
$project: {...}
},
{
// Some things you can match only after projection or grouping, so do it now.
$match: {...}
}
];
// Copy filtering elements from the pipeline - this is the same for both counting number of fileter elements and for pagination queries.
var aggregationPaginated = aggregation.slice(0);
// Count filtered elements.
aggregation.push(
{
$group: {
_id: null,
count: { $sum: 1 }
}
}
);
// Sort in pagination query.
aggregationPaginated.push(
{
$sort: sorting
}
);
// Paginate.
aggregationPaginated.push(
{
$limit: skip + length
},
{
$skip: skip
}
);
// I use mongoose.
// Get total count.
model.count(function(errCount, totalCount) {
// Count filtered.
model.aggregate(aggregation)
.allowDiskUse(true)
.exec(
function(errFind, documents) {
if (errFind) {
// Errors.
res.status(503);
return res.json({
'success': false,
'response': 'err_counting'
});
}
else {
// Number of filtered elements.
var numFiltered = documents[0].count;
// Filter, sort and pagiante.
model.request.aggregate(aggregationPaginated)
.allowDiskUse(true)
.exec(
function(errFindP, documentsP) {
if (errFindP) {
// Errors.
res.status(503);
return res.json({
'success': false,
'response': 'err_pagination'
});
}
else {
return res.json({
'success': true,
'recordsTotal': totalCount,
'recordsFiltered': numFiltered,
'response': documentsP
});
}
});
}
});
});