(Пожалуйста, найдите мое решение в моем сообщении с ответом ниже)
надеюсь, у тебя все хорошо. Мой вопрос сегодня о том, как нравится/не нравится простая система с nodeJs, и данные находятся в MongoDB.
Мне дали реализацию серверной части API. Фронтенд уже сделан и его не трогать.
Цель API — позволить людям публиковать острые соусы с выбором параметров. Каждый пользователь должен войти в систему для выполнения любого действия! На этом этапе разработки любое обновление, выполненное на любой странице, отправляет пользователя обратно на страницу входа.
Я нахожусь в самой последней задаче, которую мне нужно выполнить, а именно: реализовать маршрут для простой системы «нравится / не нравится». Эта система имеет следующие настройки:
если пользователь нажимает «большой палец вверх», внешний интерфейс отправляет числовое значение «1» (далее называемое «likeStatus»)
если пользователь нажимает «большой палец вниз», внешний интерфейс отправляет «-1», например, статус
если пользователь отменяет щелчок по понравившемуся/не нравится, интерфейс отправляет «0» likeStatus
когда пользователь нажимает на любую кнопку, идентификатор пользователя сохраняется в одном из двух массивов, встроенных в объектную модель: usersLiked или usersDisliked в зависимости от выбора, сделанного пользователем. Обратите внимание, что оба массива включены в модель «соус», поэтому их нельзя найти в пользовательской модели.
на стороне интерфейса, когда пользователь нажимает на любой большой палец, другой становится серым, что не позволяет им щелкнуть по нему. Пользователь должен отменить первоначальный выбор, чтобы иметь возможность выбрать другой.
Моя проблема в том, что я не могу отслеживать отмены кликов пользователя, когда они возвращаются с «1» или «-1» на «0 (ноль)». И это потому, что я не знаю, как проверить, где был пользователь, прежде чем он стал равным нулю. Мне важно обязательно удалить его из правильного массива и уменьшить правильный счетчик, а не оба или неправильный.
Попробовав то, что я описываю ниже, я ищу способ проверить:
или
Я хотел использовать цепочку if/else как для проверки likeStatus, так и для поиска в массивах usersLiked и usersDisliked, чтобы увидеть, был ли там userId (здесь называемый «лайкер»). Если бы это было в userLiked, то я мог бы уменьшить счетчик лайков и наоборот, если бы id был в userDisliked. Но оба массива рассматриваются как «неопределенные» и поэтому не могут быть прочитаны.
Вот весь код похожего/непохожего маршрута, который я построил до сих пор:
exports.likeSauce = (req,res,next) =>{
const liker = req.body.userId;
let likeStatus = req.body.like;
let usersLiked = req.body.usersLiked;
let usersDisliked = req.body.usersDisliked;
if (likeStatus===1){
sauce.updateOne({_id:req.params.id}, {$inc:{likes:+1},$push:{usersLiked:liker}})
.then(()=>res.status(201).json({message:'you liked this sauce'}))
.catch(error=>res.status(400).json({error}))
} else if (likeStatus===-1) {
sauce.updateOne({_id:req.params.id}, {$inc:{dislikes:+1},$pull:{usersLiked:liker},$push:{usersDisliked:liker}})
.then(()=>res.status(201).json({message:'you disliked this sauce'}))
.catch(error=>res.status(400).json({error}))
} else if (likeStatus===0){
if (usersLiked.includes(liker)){
sauce.updateOne({_id: req.params.id}, { $inc: { likes: -1}, $pull: { usersLiked:liker}})
} else if (usersDisliked.includes(liker)){
sauce.updateOne({_id: req.params.id}, { $inc: { dislikes: -1}, $pull: { usersDisliked:liker}})
}
}
}
вот модель "соуса" с обоими массивами в конце:
const mongoose = require('mongoose');
const sauceSchema = mongoose.Schema({
userId: {type:String},
name: {type:String, required:true},
manufacturer:{type:String, required:true},
description:{type:String, required:true},
mainPepper: {type:String, required:true},
imageUrl:{type:String, required:true},
heat: {type:Number, required:true},
likes: {type:Number},
dislikes : {type:Number},
usersLiked : {type:["String <userId>"]},
usersDisliked: {type:["String <userId>"]},
});
module.exports = mongoose.model('sauce', sauceSchema);
этот вопрос перекликается с этим, но предоставленное там решение мне не очень помогло (кстати, та же ситуация)
Вот и все, я благодарю вас за чтение моего длинного поста и за любую помощь, которую вы можете оказать.
И почему в запросе идут req.body.usersLiked и req.body.usersDisliked? Есть ли какое-то промежуточное ПО, которое устанавливает те. Они, конечно, не должны исходить от клиента. Можете ли вы ТОЧНО показать, какие данные поступают от клиента?
Этот код также выглядит так, как будто он может быть уязвим для условий гонки, потому что у вас есть массив данных из базы данных, находящихся в памяти во время асинхронной операции (что дает другим запросам возможность запускаться и конфликтовать с вашими намерениями или перезаписывать их).
Привет @jfriend00, спасибо за ваши комментарии, но мне немного неловко отвечать вам. Во-первых, мы уже находимся на странице определенного соуса, поэтому маршрут просто выбирает идентификатор соуса. Во-вторых, они дали нам массивы для вставки в модель, но, я думаю, нет промежуточного программного обеспечения для их установки. Вы спрашиваете, что Клиент отправляет? хорошо, console.info(req.body) возвращает объект с userId и 1, или 0, или -1. Третий момент: интересно, я проверю это.
Откуда массив? Вы показываете, что это исходит от req.body, что обычно означает, что оно исходит от клиента. Если это так, то это действительно плохой дизайн. Клиент никогда не должен управлять массивом. Клиент должен отправить вам одну модификацию, которую он хочет внести в массив, и вы соответствующим образом обновите базу данных, объединив их добавочную модификацию с текущими данными из базы данных.
@jfriend00 jfriend00, насколько я знаю, массивы были реализованы в модели, которую вы найдете в конце моей ОП, но помимо этого мой сеанс просмотра передней папки ничего не дал об этих массивах. И ничего больше сзади тоже
Хорошо, теперь я вижу, что, возможно, идентификатор соуса исходит от req.params.id, который анализируется из URL-адреса. Я понимаю, что один сейчас. Вам нужно знать, откуда берутся массивы, чтобы убедиться, что это не создает плохой дизайн или ошибочную реализацию в условиях гонки.
Я спрашиваю, откуда взялись req.body.usersLiked и req.body.usersDisliked?
Я могу сказать вам, что эти массивы появляются только дважды во всем проекте: первый в файле модели соуса, воспроизведенном в OP, и второй в обсуждаемом здесь маршруте. Так что только в бэкенде проекта, а не во фронте, вообще нет.
Ну, они не появляются волшебным образом из воздуха. Вы должны упустить что-то, что их заполняет, либо в промежуточном программном обеспечении, либо в клиенте.
Я проверю это и вернусь, когда найду решение. еще раз спасибо за все ваши комментарии до сих пор :-)
Возможно, какое-то промежуточное программное обеспечение загружает весь документ соуса, и эти поля не названы конкретно в этом коде, а назначены req.body в промежуточном программном обеспечении.
Давайте продолжим обсуждение в чате.
Я разместил резюме кода в чате, указанном выше. Думаю, именно в этом маршруте создания соуса создаются массивы?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Наконец-то я решил свою проблему и подумал, что могу поделиться ею со всеми вами. Это не очень элегантное и не идеально динамичное решение, но оно, по крайней мере, помогло мне решить мою проблему. В идеале мне бы хотелось динамически увеличивать счетчики лайков и дизлайков, применяя usersLiked и usersDislikedarray.length, но если у кого-то есть идея, буду рад. Без лишних слов, вот код:
exports.likeSauce = (req, res, next) => {
const liker = req.body.userId;
let likeStatus = req.body.like;
sauce.findOne({ _id: req.params.id })
.then((votedSauce) => {
if (likeStatus === 1) {
sauce.updateOne({ _id:req.params.id }, { $push: { usersLiked: liker }, $inc: { likes:1 }})
.then(() => res.status(201).json({ message: 'you liked this sauce' }))
.catch(error => res.status(400).json({ error }))
} else if (likeStatus === -1) {
sauce.updateOne({ _id: req.params.id }, { $inc: { dislikes: 1 }, $push: { usersDisliked: liker }})
.then(() => res.status(201).json({ message: 'you disliked this sauce' }))
.catch(error => res.status(400).json({ error }))
} else if (likeStatus === 0) {
if (votedSauce.usersLiked.includes(liker)) {
sauce.update({ _id: req.params.id }, { $inc: { likes: -1 }, $pull: { usersLiked: liker }})
.then(() => res.status(201).json({ message:'you un-liked this sauce' }))
.catch(error => res.status(400).json({ error }))
} else if (votedSauce.usersDisliked.includes(liker)) {
sauce.updateOne({ _id: req.params.id }, { $inc: { dislikes: -1 }, $pull: { usersDisliked: liker }})
.then(() => res.status(201).json({ message:'you un-disliked this sauce' }))
.catch(error => res.status(400).json({ error }))
}
}
})
.catch(error => res.status(400).json({ error }))
};
Почему в вашем маршруте
likeSauceзапрос не отправляет вам соус, чей статус лайка изменяется? Я не понимаю, как можно поступать правильно, не зная, какой соус нравится?