Проблема с обновлением логического значения с помощью функции save() с помощью мангуста

#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» на серверную часть, и это сработало. Спасибо за помощь!