2011-06-27 11 views
9

自分のブログプラットフォームにmongodbを使用しています。ユーザーは自分のブログを作成できます。すべてのブログからのすべてのエントリーはエントリーコレクションにあります。エントリのドキュメントは次のようになります。Mongodb:各グループの上位N行を選択してください

{ 
    'blog_id':xxx, 
    'timestamp':xxx, 
    'title':xxx, 
    'content':xxx 
} 

質問によると、各ブログの最後の3つのエントリを選択する方法はありますか?

答えて

1

あなたは二つのものと一緒に暮らすことができる場合は、基本的なモンゴでこれを行うための唯一の方法:

  • ご記入文書の追加フィールドのは、それを呼びましょう、「年齢」
  • 新しいブログエントリが服用を追加のアップデート

その場合は、ここにあなたがそれを行う方法は次のとおりですねっを作成する際に

  1. あなたの通常の挿入を行い、このアップデートを実行して、すべての投稿の年齢を増やしてください(このブログのために挿入したものを含む):

    db.entries.update({blog_id:BLOG_ID} $ INC:1}}、)、偽真

  2. 照会すると、各ブログの最新の3つの項目を返します。次のクエリを使用します(

    db.entries.findを{年齢:{$ LTE:3}、タイムスタンプ:{$ GTE:STARTOFMONTH、$のLT:ENDOFMONTH}})ソート({blog_id:1、年齢:1})

このソリューションは実際には並行性に安全です(重複するエントリはありません)。マップを使用して

+0

あなたのアイデアを得ました。私はそんなことは考えなかった。新しい投稿を作成するときに追加の更新が問題になることはありません。しかし、ユーザーが投稿を削除すると、他のすべての投稿の「年齢」フィールドを更新する必要があります。その更新は、削除された投稿に「年齢」<= 3が設定されている場合にのみ発生するように制限できます。私は何か不足していますか? – Tacaza

+0

はい、年齢が<3になるように更新を制限するべきではありません。これは、年齢が重複してしまうためです。インプレースアップデートは非常に高速ですので、問題ではありません。削除とは、エントリを削除し、age> deleted_post.ageの場合は年齢を1ずつ減らすことを意味します。がんばろう。 –

+0

これは絶対に意味があります。あなたの提案をありがとう! – Tacaza

0

グループ(集約)でも可能ですが、フルテーブルスキャンが作成されます。

本当に正確に3が必要ですか、または制限を設定することはできますか?たとえば、先週/過去の投稿は最大3件ですか?

+0

理想的には私は正確に3を選択したいが、私は、データの非正規化を除いて解決策を見つけることができない場合は先月から最大3つのポストは十分に良いことができます。これがどのようにしてどうすればよいのか、私に例を教えてください。すべてのmongodbの地図から私が読んだチュートリアルを減らすには、統計(集計)を計算する方法のみを示します。 – Tacaza

1

この答えは別の質問からdrcostaによって減らすあなたが最初のイニシャルを行い、その後、blog_idtimestamp分野でコレクション内の文書をソートする必要があるトリック

In mongo, how do I use map reduce to get a group by ordered by most recent

mapper = function() { 
    emit(this.category, {top:[this.score]}); 
} 

reducer = function (key, values) { 
    var scores = []; 
    values.forEach(
    function (obj) { 
     obj.top.forEach(
     function (score) { 
      scores[scores.length] = score; 
     }); 
    }); 
    scores.sort(); 
    scores.reverse(); 
    return {top:scores.slice(0, 3)}; 
} 

function find_top_scores(categories) { 
    var query = []; 
    db.top_foos.find({_id:{$in:categories}}).forEach(
    function (topscores) { 
     query[query.length] = { 
     category:topscores._id, 
     score:{$in:topscores.value.top} 
     }; 
    }); 
    return db.foo.find({$or:query}); 
8

をしましたグループは、降順で元の文書の配列を作成します。その後、最初の3つの要素を返すためにドキュメントで配列をスライスすることができます。

直感は、この例で続けることができます。

db.entries.aggregate([ 
    { '$sort': { 'blog_id': 1, 'timestamp': -1 } }, 
    {  
     '$group': { 
      '_id': '$blog_id', 
      'docs': { '$push': '$$ROOT' }, 
     } 
    }, 
    { 
     '$project': { 
      'top_three': { 
       '$slice': ['$docs', 3] 
      } 
     } 
    } 
]) 
+0

ありがとう、華麗 –

関連する問題