2017-11-13 3 views
0

Ich möchte eine Liste der Beiträge aus der Datenbank basierend auf likes und date zeigen, denken Sie an die grundlegende "Trending" Artikel Seite.Mongoose Abfrage für "heiße" Beiträge

Ich möchte eine Formel wie score = likes/daysSinceCreation verwenden und dann die ersten 10 Beiträge basierend auf dieser Punktzahl erhalten.

Wie kann ich diese Sortierfunktion mit mongoDB/Mongoose hinzufügen?

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

Zur Zeit kann ich Top-Beiträge in der letzten Woche erhalten (finden, wenn das Erstellungsdatum größer als letzte Woche und um nach Punkten), aber wie kann ich eine komplexere Sortierfunktion implementieren, ohne alle Elemente aus der bekommen DB?

zB: Heute ist Freitag

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 

sortierte Liste von IDs ist: [4 (Th), 5 (Fr), 2 (Tu), 3 (We), 1(Mo)]

+0

Sie suchen, um sie zu paginieren, oder nur eine feste "Top 10"? Die einzige Möglichkeit, dies zu tun, ist die Verwendung der Aggregationspipeline. Aber wenn Sie es so machen, könnte es schwer werden, abhängig davon, wie oft es aufgerufen wird und wie viele Daten Sie haben, da Sie nach einer Berechnung sortieren würden. Ich würde höchstwahrscheinlich die IDs oder die Dokumente selbst in einer separaten "temporären" Sammlung aggregieren und dann nach dieser Sammlung fragen. Es ist ziemlich abhängig von der Größe Ihrer Daten, Abfrage/Berechnung/Update-Frequenzen, Paginierung, etc. – cdbajorin

+0

Nun, es wird wahrscheinlich die Homepage der Website sein, wo Trending-Elemente angezeigt werden, denken Sie an reddit. So wird jeder Benutzer die Abfrage auslösen. Ich denke, es könnte zwischengespeichert und nur einmal pro Stunde oder so aktualisiert werden, das könnte funktionieren, denke ich. – Cristy

+0

Können Sie Ihr 'Post'-Schema hinzufügen? – cdbajorin

Antwort

1

Dies wird ein neues Dokument in einer "trendingposts" Tabelle erstellen:

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(...) 

ein paar zu beachtende Dinge:

  1. Bei der Verwendung von Mongo 3.4+ die $ Projektphase kann auch geschrieben werden als:

    { 
        $addFields: { 
         trendScore: { 
          $divide: [ "$score", {$subtract: [new Date(), "$createdAt"]} ] 
         } 
        } 
    }, 
    
  2. { $min: now } nur ein Hack ist der Minimalwert von now auf jedes Dokument zu greifen, auch wenn sie den gleichen Wert für alles von ihnen.

  3. "$$ROOT" ist das gesamte aktuelle Dokument. Dies bedeutet, dass Ihr Endergebnis ein einzelnes Objekt mit der Form sein:

    { 
        "_id" : ObjectId("5a0a2fe912a325eb331f2759"), 
        "evaluatedAt" : ISODate("2017-11-13T23:51:56.051Z"), 
        "posts" : [/*10 `post` documents, sorted by trendScore */] 
    } 
    

Anschließend können Sie abfragen mit:

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

Wenn Ihre Beschreibung/Titel häufig ändern, statt $push ing Das gesamte Dokument in, Sie könnten einfach die IDs schieben und sie für eine $in Abfrage auf Ihre Beiträge verwenden, um die neuesten Daten zu gewährleisten.

+0

Warum wird 'evaluatedAt' benötigt? – Cristy

+0

Sortierung/Abfrage in der Zukunft.Es ist nicht notwendig, aber es könnte nützlich sein, wenn Sie zurückblicken und den Satz von Beiträgen analysieren möchten, während sie sich ändern. – cdbajorin