2017-12-14 30 views
0

グループとソートされた集計のトップ10と最後の10の結果を表示する必要があるユースケースがあります。私は$limitを使用しようとしましたが、次のアグリゲーターが完全なデータを処理することはできません。MongoDBコレクションから最初のNレコードと最後のNレコードを取得します

db.collection.aggregate([groupAggregator, sortAggregator, { $limit: 10 }, /*only 10 records available*/] 

パイプラインの途中でコレクション全体で集計を実行するにはどうすればよいですか?私はMongoDB 3.2.9を使用しています。それが不可能ならUNION 2件の集計top 10 (ASC SORTED) 2つ目last 10 (DESC SORTED)である第1の1の方法があり

は、グループ集計のためにそれをがなかったら、私はdb.collection.find({}).sort().filter()戦略を使用していただろうが、グループが行う必要があります。グループ集合から得られる

データは

{_id: "", ..., avg_count: 10} 
{_id: "", ..., avg_count: 1} 
{_id: "", ..., avg_count: 2} 
{_id: "", ..., avg_count: 5} 
{_id: "", ..., avg_count: 8} 
{_id: "", ..., avg_count: 3} 
{_id: "", ..., avg_count: 4} 
{_id: "", ..., avg_count: 6} 
{_id: "", ..., avg_count: 7} 
{_id: "", ..., avg_count: 9} 

データソート集合から得

{_id: "", ..., avg_count: 1} 
{_id: "", ..., avg_count: 2} 
{_id: "", ..., avg_count: 3} 
{_id: "", ..., avg_count: 4} 
{_id: "", ..., avg_count: 5} 
{_id: "", ..., avg_count: 6} 
{_id: "", ..., avg_count: 7} 
{_id: "", ..., avg_count: 8} 
{_id: "", ..., avg_count: 9} 
{_id: "", ..., avg_count: 10} 

所望の出力:

はFETCH FIRST 2と最後の2文書

{_id: "", ..., avg_count: 1} 
{_id: "", ..., avg_count: 2} 
{_id: "", ..., avg_count: 9} 
{_id: "", ..., avg_count: 10} 

注:上記だけのサンプルデータであり、実際のデータは、正確なシリアル番号を持っていません。

+0

あなたはおそらく、いくつかのSAMを追加することができます。確かにMongoDBはうまくソート/制限の組み合わせを最適化することが可能であろうような方法より速いだろう(のみ以降V3.4から)$facetを使用するにはプレデータと目的の出力?あなたの説明に基づいて、私はあなたが何をしているかを正確に把握するのに苦労しています。 – dnickless

+0

@dnickless最新の質問をご確認ください。 –

答えて

2

正しくあなたを理解していれば、ここではその動作を得るための一つの方法だ:

db.collection.aggregate([{ 
    $sort: { "your_sort_field": 1 } // sort the data 
}, { 
    $group: { 
     _id: null, // group everything into one single bucket 
     docs: { $push: "$$ROOT" } // push all documents into an array (this will be massive for huge collections...) 
    } 
}, { 
    $project: { 
     "docsTop10": { $slice: [ "$docs", 10 ] }, // take the first 10 elements from the ASC sorted array 
     "docsBottom10": { $reverseArray: { $slice: [ "$docs", -10 ] } } // take the last 10 elements from the array but reverse their order 
    } 
}]) 

あなたは単に最終段階で$concatArraysを使用することができます1つのプロパティですべてを持っているしたい場合:

$project: { 
    "result": { $concatArrays: [ { $slice: [ "$docs", 10 ] }, { $reverseArray: { $slice: [ "$docs", -10 ] } } ] } 
} 

残念ながら、ご使用のMongoDBのバージョンにはまだ$replaceRootはありません。そうしないと、結果をよりうまくフラットにすることができます。また

$reverseArrayはどちらか、V3.2で利用可能ではないようですから、あなたは、単に$project段階の後に1つのより多くの時間をその演算子と$unwindをドロップし、$sortことができます。

{ 
    $project: { 
     _id: 0, 
     "result": { $concatArrays: [ { $slice: [ "$docs", 10 ] }, { $slice: [ "$docs", -10 ] } ] } 
    } 
}, { 
    $unwind: "$result" 
}, { 
    $sort: { "result.your_sort_field": 1 } // sort the data 
} 

別のオプションは次のようになります

db.collection.aggregate([{ 
    $facet: { // start two separate pipeline 
     "docsTop10": [ 
      { $sort: { "your_sort_field": 1 } }, // sort ASC 
      { $limit: 10 } // take top 10 
     ], 
     "docsBottom10": [ 
      { $sort: { "your_sort_field": -1 } }, // sort DESC 
      { $limit: 10 } // take top 10 
     ] 
    } 
}]) 
+0

私は注文100Kの行を扱っていますが、最初は今のところほとんど役に立たないかもしれません。残念ながら 'reverseArray'はMongo 3.2.9と互換性がありません。 –

+0

これを回避する方法を説明します。 – dnickless

+0

偉大な答え!両方の回避策をありがとう、私は '$ facet'集約を利用するためにMongo 3.6にアップグレードしました。 –

関連する問題