Я создал простое приложение MERN, где пользователи могут оценивать телефонные номера.Пользователи просто вводят номер телефона, выбирают рейтинг (1 - 5 звезд), свой город и короткий текст.Приложение имеет функцию поиска с параметрами фильтра и сортировки.Все это работает достаточно хорошо, но я думаю, что он может сломаться, когда несколько одновременных пользователей используют веб-сайт, потому что я обновляю модель телефонных номеров (mobileSchema) после того, как рейтинг (messageSchema) был отправлен - используя промежуточное ПО Mongoose (post hooks).
Например, мне нужно рассчитать количество оценок (messagesCount) для номера телефона.Я использую 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);
})
}