#node.js #mongodb #express #mongoose #concurrency
#node.js #mongodb #экспресс #мангуст #параллелизм
Вопрос:
Я пытаюсь создать систему обозначений для фильмов
Пользователь может отметить фильм в своем списке.
Всякий раз, когда пользователь нажимает на интерфейс, listId, movieId, note
они отправляются на сервер для обновления заметки. Примечание может быть установлено в значение null, но это не удаляет запись из списка.
Но если пользователь нажимает слишком много раз, фильмы totalNote
и nbNotes
полностью ломаются. Похоже, что есть какие-то проблемы с параллелизмом?
Это правильный подход к этой проблеме или я обновляю неправильно?
Схемы мангуста, связанные :
// Movie Schema
const movieSchema = new Schema({
// ...
note: { type: Number, default: 0 },
totalNotes: { type: Number, default: 0 },
nbNotes: { type: Number, default: 0 },
})
movieSchema.statics.updateTotalNote = function (movieId, oldNote, newNote) {
if (!oldNote amp;amp; !newNote) return
const nbNotes = !newNote ? -1 : (!oldNote ? 1 : 0) // If oldNote is null we 1, if newNote is null we -1
return Movie.findOneAndUpdate({ _id: movieId }, { $inc: { nbNotes: nbNotes, totalNotes: (newNote - oldNote) } }, { new: true }).catch(err => console.error("Couldn't update note from movie", err))
}
// List Schema
const movieEntry = new Schema({
_id: false, // movie makes an already unique attribute, which is populated on GET
movie: { type: Schema.Types.ObjectId, ref: 'Movies', required: true },
note: { type: Number, default: null, max: 21 },
})
const listSchema = new Schema({
user: { type: Schema.Types.ObjectId, ref: 'Users', required: true },
movies: [movieEntry]
})
API обновления сервера (добавление / удаление movieEntry аналогично $push
и $pull
вместо $set
)
exports.updateEntry = (req, res) => {
const { listId, movieId } = req.params
const movieEntry = { movieId: movieId, note: req.body.note }
List.findOneAndUpdate({ _id: listId, 'movies.movie': movieId }, { $set: { 'movies.$[elem]': movieEntry } }, { arrayFilters: [{ 'elem.movie': movieId }] })
.exec()
.then(list => {
if (!list) return res.sendStatus(404)
const oldNote = list.getMovieEntryById(movieId).note // getMovieEntryById(movieId) = return this.movies.find(movieEntry => movieEntry.movie == movieId)
Movie.updateTotalNote(movieId, oldNote, movieEntry.note)
let newList = list.movies.find(movieEntry => movieEntry.movie == movieId) // Because I needed the oldNote and findOneAndUpdate returns the list prior to modification, I change it to return it
newList.note = movieEntry.note
newList.status = movieEntry.status
newList.completedDate = movieEntry.completedDate
return res.status(200).json(list)
})
.catch(err => {
console.error(err)
return res.sendStatus(400)
})
}
Ответ №1:
Записи, которые мне нужно было обновить, были массивами, которые могли расти бесконечно, поэтому мне пришлось сначала изменить свои модели и использовать виртуальные и другую модель для записей списка.
Это упростило работу, и я смог создавать, обновлять и удалять записи проще и без каких-либо проблем с параллелизмом.
Это также могло быть не проблемой параллелизма, а проблемой транзакции.