javascript - Mongoose 数据流

标签 javascript mongodb express mongoose

我构建了一个简单的 MERN 应用程序,用户可以在其中对电话号码进行评分。用户只需填写电话号码、选择评级(1 - 5 星级)、所在城市和短文本。该应用程序具有带有过滤和排序选项的搜索功能。这一切都在 ATM 上运行得足够好,但我认为当多个并发用户使用该网站时,它可能会崩溃,因为我在提交评级(messageSchema)后更新了电话号码模型(mobileSchema) - 使用 Mongoose 中间件(后 Hook )。

例如,我需要计算电话号码的评分数(messagesCount)。我使用 Message.countDocuments({ mobile: mobile._id }) 来实现此目的。但是,我还需要更新电话号码的其他属性(mobileSchema - lastMessageDate、globalRating、averageRating),以便操作需要一些时间。我相信当 2 个用户同时提交评分时,评分数可能不正确 - 评分数 (messagesCount) 会增加 1,而不是 2。

有更好的方法吗?在前一个 post hook 完成后可以触发 post hook 吗?

示例代码:

const mobileSchema = new Schema({
    number: { type: String, required: true },
    plan: { type: String, required: true },
    date: { type: Date, default: Date.now, required: true, index: 1 },
    messagesCount: { type: Number, default: 0, index: 1 },
    lastMessageDate: { type: Date, index: 1 },
    // normal mean
    globalRating: { type: Number, default: 0, index: 1 },
    // weighted mean
    averageRating: { type: Number, default: 0, index: 1 }
});

const messageSchema = new Schema({
    comment: { type: String, required: true },
    city: { type: Schema.Types.ObjectId, ref: 'City', required: true, index: 1 },
    rating: { type: Number, required: true, index: 1 },
    date: { type: Date, default: Date.now, required: true, index: 1 },
    mobile: { type: Schema.Types.ObjectId, ref: 'Mobile', required: true },
    user: { type: Schema.Types.ObjectId, ref: 'User', required: true }
});

messageSchema.post('save', function (message, next) {
    const messageModel = this.constructor;
    return updateMobile(messageModel, message, next, 1);
});

const updateMobile = (messageModel, message, next, addMessage) => {
    const { _id } = message.mobile;
    const cityId = message.city._id;
    const lastMessageDate = message.date;
    let mobile;
    hooks.get(Mobile, { _id })
        .then(mobileRes => {
            mobile = mobileRes;
            return Message.countDocuments({ mobile: mobile._id })
        })
        .then(messagesCount => {
            if (messagesCount <= 0) {
                const deleteMobile = Mobile.findOneAndDelete({ _id: mobile._id })
                const deleteSeen = SeenMobile.findOneAndDelete({ mobile: mobile._id, user: message.user._id })
                const cityMobile = updateCityMobile(messageModel, mobile, cityId)
                Promise.all([deleteMobile, deleteSeen, cityMobile])
                    .then(() => {
                        return next();
                    })
                    .catch((err) => {
                        console.log(err);
                        return next();
                    })
            }
            else {
                if (addMessage === -1) lastMessageDate = mobile.lastMessageDate;
                const ratings = hooks.updateGlobalRating(mobile, messageModel)
                    .then(() => hooks.updateAverageRating(mobile, messageModel))
                    .then(() => {
                        return new Promise((resolve, reject) => {
                            mobile.set({
                                messagesCount,
                                lastMessageDate
                            });
                            mobile.save((err, mobile) => {
                                if (err) return reject(err);
                                resolve();
                            });
                        })
                    })
                const cityMobile = updateCityMobile(messageModel, mobile, cityId)
                Promise.all([ratings, cityMobile])
                    .then(([ratings, cityMobile]) => {
                        return next();
                    })
                    .catch(err => console.log(err))
            }
        })
        .catch(err => {
            console.log(err);
        })
}

最佳答案

我认为你的方法总是会遇到异步问题。我不相信你可以“同步”钩子(Hook);似乎与 MongoDB 的一切真相背道而驰。然而,在较高的层面上,您可能会更成功地在运行时获取总计/摘要,而不是试图使它们始终保持同步。例如,如果您需要给定移动设备的消息总数,为什么不:

Messages.find({mobile: mobile._id})

然后统计结果?这将节省您存储摘要并保持更新的时间。但是,我也认为您当前的方法可能有效,但您可能需要废弃“countDocuments”。一些对异步更友好的东西,比如:

Mobile.aggregation([
    { $match: { _id: mobile._id } },
    { $add: [ "$mobile.messagesCount", 1 ] }
]);

最终,我认为如果您将消息存储为 Mobile 内部的数组,那么您的设计将会得到加强,这样您就可以将消息推送到上面。但为了直接回答这个问题,聚合应该保持一切整洁。

关于javascript - Mongoose 数据流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53508827/

相关文章:

node.js - Express:将文档嵌入现有文档中

node.js - Express js 错误处理

javascript - 学习Javascript的bind方法讲解

javascript - MongoDB 计算对象内的对象

javascript - es6 javascript推荐使用三元运算符应用模板文字的方法?

c++ - 使用 C++ 驱动程序在 mongoDB 中使用 $elemMatch 投影查找查询

mysql - 我们应该在 MySQL 中即时创建的表中拆分数据还是使用其他 DBMS?

javascript - 在 POST 请求中获取表单名称 Express JS(使用 EJS)

javascript - 用于更改 iFrame 的单选按钮不起作用

javascript - 将当前日期作为占位符最初放置在输入字段 datepicker bootstrap 中