2017-11-13 4 views
0

likesdateに基づいてデータベースからの投稿のリストを表示するには、基本的な "トレンド"アイテムのページを考えてください。"ホット"投稿のマングースクエリ

score = likes/daysSinceCreationのような公式を使用して、このスコアに基づいて最初の10の投稿を取得します。

mongoDB/Mongooseでどのようにソート機能を追加できますか?が、私はからすべての項目を得ることなく、より複雑なソート機能を実装する方法

Posts.find().sort(???).limit(10).then(posts => console.log(posts));

は現在、私は先週のトップのポストを得ることができます(先週とスコアによって順位より大きい作成日時があれば見つけます。) DB?

例: 今日は金曜日

ID CREATION_DAY LIKES 
1 Monday   4  // score is 5/5 = 0 
2 Tuesday   10 // score is 10/4 = 2 
3 Wednesday  3  // score is 3/3 = 1 
4 Thursday  20 // score is 20/2 = 10 
5 Friday   5  // score is 5/1 = 5 
IDの

ソートされたリストは次のとおりです。[4 (Th), 5 (Fr), 2 (Tu), 3 (We), 1(Mo)]

+0

ページめくりをしたいのですか、あるいは単に固定した「トップ10」ですか?私がこれを行うと考えることができる唯一の方法は、集約パイプラインを使用することです。しかし、あなたがそれをやっているなら、計算後にソートするので、呼び出される頻度やデータの量によっては重くなる可能性があります。私はおそらくIDまたはドキュメント自体を別の "一時的な"コレクションに集約し、そのコレクションを照会します。あなたのデータのサイズ、クエリ/計算/更新頻度、ページ設定などにかなり依存しています。 – cdbajorin

+0

これはおそらく、トレンドアイテムが表示されているサイトのホームページで、redditを考えています。したがって、すべてのユーザーがクエリをトリガします。私はそれがキャッシュされ、1時間に1回しか更新できないと思います。 – Cristy

+0

'Post'スキーマを追加できますか? – cdbajorin

答えて

1

これは "trendingposts" テーブルに新しいドキュメントを作成します。

const fiveDaysAgo = new Date(Date.now() - (5 * 24 * 60 * 60 * 1000)); 
const oid = new ObjectId(); 
const now = new Date(); 

Posts.aggregate([ 
    { 
     $match: { 
      createdAt: { 
       $gte: fiveDaysAgo 
      }, 
      score: { 
       $gt: 0 
      } 
     } 
    }, 
    { 
     $project: { 
      _id: true, 
      createdAt: true, 
      updatedAt: true, 
      title: true, 
      description: true, 
      score: true, 
      trendScore: { 
       $divide: [ "$score", {$subtract: [new Date(), "$createdAt"]} ] 
      } 
     } 
    }, 
    { 
     $sort: { 
      trendScore: -1 
     } 
    }, 
    { 
     $limit: 10 
    }, 
    { 
     $group: { 
      _id: { $min: oid }, 
      evaluatedAt: { $min: now }, 
      posts: { $push: "$$ROOT"} 
     } 
    }, 
    { 
     $out: "trendingposts" 
    } 
]) 
    .then(...) 

数注釈する内容:

  1. $プロジェクト段ものように書くことができ3.4+モンゴを使用している場合:

    { 
        $addFields: { 
         trendScore: { 
          $divide: [ "$score", {$subtract: [new Date(), "$createdAt"]} ] 
         } 
        } 
    }, 
    
  2. { $min: now }は、それがすべてで同じ値だにも関わらず、各文書にnowの最小値を取得するだけでハックですそのうちの。

  3. "$$ROOT"は、現在のドキュメント全体です。

    あなたは、その後で問い合わせることができ
    { 
        "_id" : ObjectId("5a0a2fe912a325eb331f2759"), 
        "evaluatedAt" : ISODate("2017-11-13T23:51:56.051Z"), 
        "posts" : [/*10 `post` documents, sorted by trendScore */] 
    } 
    

:あなたの説明/タイトルが頻繁に変更している場合は、代わり$push INGの、

TrendingPosts.findOne({}) 
    .sort({_id: -1}) 
    .then(trendingPost => console.log(trendingPost)); 

これはあなたの最終的な結果は、フォームを持つ単一のオブジェクトであることを意味します最新のデータを保証するために、IDをプッシュして投稿の$inクエリに使用するだけで済みます。

+0

なぜ 'evaluateAt'が必要ですか? – Cristy

+0

今後の並べ替え/クエリ。これは必須ではありませんが、変更された投稿のセットを振り返って分析したい場合に便利です。 – cdbajorin

関連する問題