繁体   English   中英

猫鼬数据流

[英]Mongoose data flow

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

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

有没有更好的方法? 前一个挂钩已经完成后,可以解雇一个挂钩吗?

样例代码:

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);
        })
}

我认为您总是会在使用方法时遇到异步问题。 我不相信您可以“同步”这些钩子; 似乎有悖于MongoDB的一切。 但是,从较高的层次上讲,您可能会在运行时获取总计/摘要方面取得更大的成功,而不是尝试使它们始终保持同步。 例如,如果您需要给定移动设备的消息总数,为什么不这样做:

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

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

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

最终,我认为如果将Messages作为数组存储在Mobile中,则您的设计将会得到加强,因此您可以将消息推送到其中。 但是要直接回答这个问题,聚合应该使一切保持整洁。

我找到了这个答案: 在MongoDB中锁定文档

我将在后挂接中计算出我需要的所有值(messagesCount,globalRating等),然后在最终的findOneAndUpdate操作期间检查移动文档是否具有相同的__v(版本)值(因为此操作将文档锁定并可以递增__v) )。 如果它具有不同的__v,那么我将再次调用post钩子,以确保它将计算正确的值。

首先,我们需要在此处修复一些数据库结构

移动架构

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 }
});

评分系统(获取所有评分或将其设为一组)(100个评分后的分子和分母很难读取每个评分),也可以检查移动设备

const ratingSchema = new Schema({
  mobile: { type: String, required: true },
  commmentId:{type:String, required: true, index: 1}
  rate: { type: Number required: true,  },
  //rating: { type: Number, required: true, index: 1 },
  timestamp: { type: Date, default: Date.now, required: true, index: 1 }
  denominator:{ type: Number},
  numerator:{type:Number}
});

谢谢

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM