8

たくさんの記事があり、人々が好きな記事に投票できるWebサイトがあるとします。

特定の時間(過去1時間、最終日、先週)内に投票数が最も多い記事を、投票数順にクエリして取得できるようにしたいと思います。

MongoDBでいつものように、これを実装する方法はいくつかありますが、どれが正しいかわかりません。

  • 投票の配列を含む投稿ドキュメント-投票自体は、ユーザーID、ユーザー名、投票日を含むドキュメントです。
    {
    "_id": "ObjectId(xxxx)",
    "title": "Post Title",
    "postdate": "21/02/2012+1345",
    "summary": "Summary of Article",

    "Votes": [
        {
            "userid":ObjectId(xxxx),
            "username": "Joe Smith",
            "votedate": "03/03/2012+1436"
        },
            ]
     }
  • 個々の投票の詳細と投票された投稿への参照を含む、個別の投票コレクション:
{
    "_id": "ObjectId(xxxx)",
    "postId": ObjectId(xxxx),
    "userId": ObjectId(xxxx),
    "votedate": "03/03/2012+1436"
}

最初のものはもっとDocumenteyですが、過去24時間で最も多くの票を獲得したドキュメントを取得するためにvotes配列をクエリする方法がわかりません。

投票ごとにグループ化された投票数を照会する方が簡単なので、2番目のものに傾いていますが、それがどれほどうまく機能するかはわかりません。これはリレーショナルデータベースで行う方法ですが、あまり文書化されていないようですが、問題があるかどうかはわかりませんね。

または、2つの組み合わせを使用しますか?また、ページが読み込まれるたびに、このタイプの集計クエリをリアルタイムで実行します。または、クエリを1分に1回実行して、結果をクエリ結果コレクションに保存しますか?

このスキーマをどのように実装しますか?

4

2 に答える 2

10

全体的な投票数を追跡する一般的な方法は、投稿ドキュメントの投票数を保持し、新しい値を投票配列にプッシュするときにそれをアトミックに更新することです。

これは単一の更新であるため、カウントが配列内の要素の数と一致することが保証されます。

集計の数が固定されていて、サイトが非常に混雑している場合は、このパラダイムを拡張して、月、日、時間などの追加のカウンターを増やすことができますが、すぐに手に負えなくなる可能性があります。したがって、代わりに新しいAggregation Framework(2.1.2 devリリースで利用可能、リリース2.2で本番環境になります)を使用できます。Map/ Reduceよりも使用が簡単で、特に次の場合に必要な計算を非常に簡単に実行できます。投票日をISODate()タイプとして保存するように注意してください。

今月のトップ投票ゲッターの集計クエリの一般的なパイプラインは、次のようになります。

today = new Date();
thisMonth = new Date(today.getFullYear(),today.getMonth());
thisMonthEnd = new Date(today.getFullYear(),today.getMonth()+1);

db.posts.aggregate( [
    {$match: { "Votes.votedate": {$gte:thisMonth, $lt:thisMonthEnd} } },
    {$unwind: "$Votes" },
    {$match: { "Votes.votedate": {$gte:thisMonth, $lt:thisMonthEnd} } },
    {$group: { _id: "$title", votes: {$sum:1} } },
    {$sort: {"votes": -1} },
    {$limit: 10}
] );

これにより、パイプラインへの入力が、投票日をカウントしている月に一致させることで投票がある投稿に制限され、配列を「巻き戻し」て投票ごとに1つのドキュメントを取得し、「groupby」と同等の方法で各タイトルのすべての投票を合計します。 (タイトルは一意だと思います)。次に、投票数の降順で並べ替え、出力を最初の10に制限します。

また、その月の日ごとに投票を集計して、投票に最もアクティブな日を確認することもできます。

db.posts.aggregate( [
    {$match: { "Votes.votedate": {$gte:thisMonth, $lt:thisMonthEnd} } },
    {$unwind: "$Votes" },
    {$match: { "Votes.votedate": {$gte:thisMonth, $lt:thisMonthEnd} } },
    {$project: { "day" : { "$dayOfMonth" : "$Votes.votedate" }  } },
    {$group: { _id: "$day", votes: {$sum:1} } },
    {$sort: {"votes": -1} },
    {$limit: 10}
] );
于 2012-07-03T16:13:21.073 に答える
0

選択するスキーマは、ユースケースに大きく依存します。多数の投票/コメントを期待していて、それらが属する投稿とは別に処理したい場合は、postIDを「foriegn」として別のコレクションに保持することができます。 key'..ただし、特定の投稿をロードするときにすべての投票をロードする必要があり、投票自体がそれらを格納する投稿なしでは意味がない場合は、埋め込みに進みます(あなたの場合、最初の) アプローチ。

于 2012-07-03T14:27:34.590 に答える