javascript - Mongoose 查询 "hot"帖子

标签 javascript node.js mongodb mongoose trending

我想根据喜欢日期显示数据库中的帖子列表,想想基本的“趋势”项目页面。

我想使用像 score = likes/daysSinceCreation 这样的公式,然后根据这个分数获取前 10 个帖子。

如何使用 mongoDB/Mongoose 添加排序功能?

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

目前我可以获得上周的热门帖子(查找创建日期是否大于上周并按分数排序),但是如何在不从数据库获取所有项目的情况下实现更复杂的排序功能?

例如: 今天是星期五

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)]

最佳答案

这将在“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. 如果使用 Mongo 3.4+,$project 阶段也可以写成:

    {
        $addFields: {
            trendScore: {
                $divide: [ "$score", {$subtract: [new Date(), "$createdAt"]} ]
            }
        }
    },
    
  2. { $min: now } 只是一种获取每个文档上 now 的最小值的 hack,即使它对于所有文档来说都是相同的值他们。

  3. "$$ROOT" 是整个当前文档。这意味着您的最终结果将是具有以下形式的单个对象:

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

然后您可以使用以下方式查询:

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

如果您的描述/标题经常更改,您可以只推送 ID 并将其用于 $in 查询,而不是 $push 整个文档在您的帖子上,以保证最新数据。

关于javascript - Mongoose 查询 "hot"帖子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47274340/

相关文章:

node.js - MongoDB - 从架构模型中仅查找 bool 值为 false 的元素

javascript - 如何从html中的javascript获取参数

javascript - Github 上的 Redux ToDo 示例

javascript - Twilio JavaScript - 从客户端到服务器的短信

windows - 在不同位置安装nodejs的最佳方法是什么

mongodb - MongoDB 分片键是否需要唯一?

javascript - 将带有特殊字符的用户输入字符串转换为正则表达式

javascript - 使用触摸事件响应日历

node.js - Mongoose 通过 ObjectId 更新文档

node.js - SailsJS : Prevent Model. create() 如果它有未声明的属性