#javascript #node.js #reactjs #mongodb #mongoose
#язык JavaScript #node.js #реагирует на #mongodb #мангуст
Вопрос:
Итак, я столкнулся с интересной проблемой, когда я смог использовать свой интерфейс для изменения логического значения на true, но не обратно на false. Мой код:
updateUser.js (серверная часть)
import express from 'express'; import mongoose from 'mongoose'; import User from '../models/userModel.js'; const app = express(); const uUserRouter = express.Router(); uUserRouter.post('/:id', (req, res) =gt; { User.findById(req.params.id) .then(user =gt; { user.username = req.body.username || user.username; user.email = req.body.email || user.email; user.password = req.body.password || user.password; user.avatar = req.body.avatar || user.avatar; user.isBanned = req.body.isBanned || user.isBanned; user.rank = req.body.rank || user.rank; user.save() .then(() =gt; res.send('User Updated!')) .catch(err =gt; res.status(400).send("Update Failed: " err.message)) }) .catch(err =gt; res.status(404).send('This user cannot be found: ' err.message)) }); export default uUserRouter;
adminPanel.component.js (интерфейс)
import axios from 'axios'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { Button, Container, Table } from 'react-bootstrap'; import { Link } from 'react-router-dom'; const Topic = props =gt; ( lt;trgt; lt;td className="tTitle"gt; {props.topic.title} lt;/tdgt; lt;td className="tDescription"gt; {props.topic.description} lt;/tdgt; lt;tdgt;lt;Button variant="secondary" onClick={() =gt; { props.deleteTopic(props.topic._id) }}gt;Deletelt;/Buttongt;lt;/tdgt; lt;/trgt; ) const User = props =gt; ( lt;trgt; lt;td className="aPAvatar"gt;lt;img src={props.user.avatar} height="15%" width="15%" alt="avatar"/gt;lt;/tdgt; lt;tdgt;{props.user.username}lt;/tdgt; lt;tdgt;{props.user.rank}lt;/tdgt; lt;tdgt;{props.user.isBanned ? lt;Button variant="primary" onClick={() =gt; { props.unBanUser(props.user._id) }}gt;Unban Userlt;/Buttongt; : lt;Button variant="warning" onClick={() =gt; { props.banUser(props.user._id) }}gt;Ban Userlt;/Buttongt;}lt;/tdgt; lt;tdgt;lt;Button variant="secondary" onClick={() =gt; { props.deleteUser(props.user._id) }}gt;Deletelt;/Buttongt;lt;/tdgt; lt;/trgt; ) class AdminPanel extends Component { constructor(props) { super(props); this.banUser = this.banUser.bind(this); this.deleteTopic = this.deleteTopic.bind(this); this.deleteUser = this.deleteUser.bind(this); this.unBanUser = this.unBanUser.bind(this); this.state = { topics: [], users: [] }; } componentDidMount() { function getTopics() { return axios.get('http://localhost:5000/forum/topics') } function getUsers() { return axios.get('http://localhost:5000/users') } Promise.all([getTopics(), getUsers()]) .then((results) =gt; { const topics = results[0].data; const users = results[1].data; this.setState({topics, users}, () =gt; { console.log(this.state); }); }).catch((e) =gt; { console.log('Error: ', e); }); } listTopics = () =gt; { return this.state.topics.map(currenttopic =gt; { return lt;Topic topic={currenttopic} deleteTopic={this.deleteTopic} key={currenttopic._id} /gt; }) } listUsers = () =gt; { return this.state.users.map(currentuser =gt; { return lt;User user={currentuser} deleteUser={this.deleteUser} banUser={this.banUser} unBanUser={this.unBanUser} key={currentuser._id} /gt; }) } banUser(id) { if (window.confirm('Are you sure you want to ban this user?')) { axios.post('http://localhost:5000/users/update/' id, {isBanned: true}) .then(res =gt; {console.log(res.data)}) .catch((e) =gt; { console.log('Error: ', e) }); window.alert('User banned successfully'); window.location.reload(); } else { window.alert('Ban Canceled'); } } unBanUser(id) { axios.post('http://localhost:5000/users/update/' id, {isBanned: false}) .then(res =gt; {console.log(res.data)}); console.log('test'); window.alert('User Unbanned'); } deleteTopic(id) { if (window.confirm('Are you sure you want to delete this topic?')) { axios.delete('http://localhost:5000/forum/topics/' id) .then(res =gt; console.log(res.data)); this.setState({ topics: this.state.topics.filter(el =gt; el._id !== id) }) window.alert('Topic Deleted'); } else { window.alert('Deletion Canceled'); } } deleteUser(id) { if (window.confirm('Are you sure you want to delete this user?')) { axios.delete('http://localhost:5000/users/delete/' id) .then(res =gt; console.log(res.data)); this.setState({ users: this.state.users.filter(el =gt; el._id !== id) }) window.alert('User Deleted') } else { window.alert('Deletion Canceled') } } render() { return ( lt;Containergt; {this.props.isLoggedIn amp;amp; this.props.rank === 'Admin' ? lt;Containergt; lt;div className="userList"gt; lt;h3gt;Userslt;/h3gt; lt;Tablegt; lt;theadgt; lt;trgt; lt;tdgt;Avatarlt;/tdgt; lt;tdgt;Usernamelt;/tdgt; lt;tdgt;Ranklt;/tdgt; lt;tdgt;Ban Hammerlt;/tdgt; lt;tdgt;Deletelt;/tdgt; lt;/trgt; lt;/theadgt; lt;tbodygt; {this.listUsers()} lt;/tbodygt; lt;/Tablegt; lt;/divgt; lt;div className="topicList"gt; lt;h3gt;Topicslt;/h3gt; lt;Tablegt; lt;theadgt; lt;trgt; lt;tdgt;Titlelt;/tdgt; lt;tdgt;Discriptionlt;/tdgt; lt;tdgt;Deletelt;/tdgt; lt;/trgt; lt;/theadgt; lt;tbodygt; {this.listTopics()} lt;/tbodygt; lt;/Tablegt; lt;Link to="/new-topic"gt; lt;Button variant="secondary" className="newTopic"gt;Create a Topiclt;/Buttongt; lt;/Linkgt; lt;/divgt; lt;/Containergt; : lt;Containergt; lt;h1gt;You must be logged in and an Administrator to view this page. lt;Link to='/'gt;Return to Homelt;/Linkgt;lt;/h1gt; lt;/Containergt; } lt;/Containergt; ) }; } const mapSateToProps = state =gt; { return { isLoggedIn: state.login.loggedIn, rank: state.login.user.rank } } export default connect(mapSateToProps)(AdminPanel);
userModel.js
import mongoose from 'mongoose'; import bcrypt from 'bcrypt' const Schema = mongoose.Schema; const SALT_WORK_FACTOR = 10; const userSchema = new Schema({ username: { type: String, required: true, trim: true, /*validate: { validator: function(username) {User.doesNotExist({ username })}, message: "Username already exists" },*/ minlength: 5 }, email: { type: String, /*validate: { validator: function(email) {User.doesNotExist({ email })}, message: "Email already exists" }*/ }, password: {type: String, required: true, index: {unique: true} }, avatar: { type: String, default: `${process.env.AWSFILESERICE}/pics/defaultPP.png` }, isBanned: { type: Boolean, default: false }, rank: { type: String, default: "Default" }, joined: { type: Date }, topics: [{type: Schema.Types.ObjectId, ref: 'Topics'}], threads: [{type: Schema.Types.ObjectId, ref: 'Topics.Threads'}], posts: [{type: Schema.Types.ObjectId, ref: 'Topics.Threads.Posts'}] }, { timestamps: true}); userSchema.pre('save', function(next) { const user = this; if (!user.isModified('password')) return next(); bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) { if (err) return next(err); bcrypt.hash(user.password, salt, function(err, hash) { if (err) return next(err); user.password = hash; next(); }); }); }); userSchema.statics.doesNotExist = async function (field) { return await this.where(field).countDocuments() === 0; } userSchema.methods.authenticate = function(candidatePassword, cb) { bcrypt.compare(candidatePassword, this.password, function(err, isMatch) { if (isMatch === true) { return cb(null, isMatch); } else { return cb(); } }) }; const User = mongoose.model('User', userSchema); export default User;
(игнорируйте закомментированное поле проверки, это незавершенный эксперимент 🙂 )
Любая другая запись в маршруте обновления (которая должна быть «пользователи/обновление/#идентификатор») работает. т. е. имя пользователя, пароль, адрес электронной почты, даже isBanned = true. Изменение его обратно на false не работает. Да, кнопка unban «работает», она отправляет запрос на серверную часть, как и предполагалось, и серверная часть отправляет «обновленное пользователем» обратно на интерфейс, но значение isBanned остается неизменным в базе данных. Я надеюсь, что просто что-то упустил, но я прочитал все, что мог, чтобы решить проблему, а также перечитал свой код… Заранее спасибо за вашу помощь!
Ответ №1:
Решение
Это решение должно работать, если вы хотите строго использовать логические значения,
... // Other user schema data isBanned: String
Затем при сохранении его используйте value.toString()
для преобразования логического значения в строку, чтобы оно сохранялось как строка, содержащая значение true/false, а затем при необходимости используйте
var originalValue = false; var toSave = originalValue.toString(); console.log(toSave ", It's a " typeof toSave); // When needed to check if the user is banned or not // I'll ignore DB things var isBanned = JSON.parse(toSave); console.log(isBanned ", It's a " typeof isBanned);
Для меня это самое простое и лучшее решение
Комментарии:
1. Согласно документам мангустов, мангуст преобразует следующее в true/false: Логические логические значения в Мангусте являются обычными логическими значениями JavaScript. По умолчанию Мангуст присваивает нижеприведенным значениям значение true: true «true» 1 » 1 «» да «Мангуст присваивает нижеприведенным значениям значение false: false «false» 0 » 0 «»нет», Что ваше решение заставило меня задуматься, что, если я просто отправил «false», а не «false» на серверную часть, и это сработало. Спасибо за помощь!