簡體   English   中英

使用 mongoose 使用 save() 更新 boolean 值時遇到問題

[英]Trouble updating boolean value with save() using mongoose

所以我遇到了一個有趣的問題,我可以使用前端將 boolean 值更改為 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) => {
  User.findById(req.params.id)
    .then(user => {
      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(() => res.send('User Updated!'))
        .catch(err => res.status(400).send("Update Failed: " + err.message))
    })
    .catch(err => 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 => (
    <tr>
        <td className="tTitle">
          {props.topic.title}
        </td>
        <td className="tDescription">
          {props.topic.description}
        </td>
        <td><Button variant="secondary" onClick={() => { props.deleteTopic(props.topic._id) }}>Delete</Button></td>
    </tr>

)
const User = props => (
    <tr>
        <td className="aPAvatar"><img src={props.user.avatar} height="15%" width="15%" alt="avatar"/></td>
        <td>{props.user.username}</td>
        <td>{props.user.rank}</td>
        <td>{props.user.isBanned ? <Button variant="primary" onClick={() => { props.unBanUser(props.user._id) }}>Unban User</Button> : <Button variant="warning" onClick={() => { props.banUser(props.user._id) }}>Ban User</Button>}</td>
        <td><Button variant="secondary" onClick={() => { props.deleteUser(props.user._id) }}>Delete</Button></td>
    </tr>
)
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) => {
                const topics = results[0].data;
                const users = results[1].data;
                this.setState({topics, users}, () => {
                    console.log(this.state);
                });

            }).catch((e) => {
                console.log('Error: ', e);
            });
        }
    listTopics = () => {
        return this.state.topics.map(currenttopic => {
            return <Topic topic={currenttopic} deleteTopic={this.deleteTopic} key={currenttopic._id} />
        })
    }

    listUsers = () => {
        return this.state.users.map(currentuser => {
            return <User user={currentuser} deleteUser={this.deleteUser} banUser={this.banUser} unBanUser={this.unBanUser} key={currentuser._id} />
        })
    }

    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 => {console.log(res.data)})
           .catch((e) => {
               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 => {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 => console.log(res.data));

            this.setState({
                topics: this.state.topics.filter(el => 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 => console.log(res.data));

            this.setState({
                users: this.state.users.filter(el => el._id !== id)
            })
            window.alert('User Deleted')
        } else {
            window.alert('Deletion Canceled')
        }
    }

    render() {
        return (
          <Container>
            {this.props.isLoggedIn && this.props.rank === 'Admin' ? 
            <Container>
                <div className="userList">
                <h3>Users</h3>
                <Table>
                    <thead>
                        <tr>
                            <td>Avatar</td>
                            <td>Username</td>
                            <td>Rank</td>
                            <td>Ban Hammer</td>
                            <td>Delete</td>
                        </tr>
                    </thead>
                    <tbody>
                        {this.listUsers()}
                    </tbody>
                </Table>

            </div>
            <div className="topicList">
                <h3>Topics</h3>
                <Table>
                    <thead>
                        <tr>
                            <td>Title</td>
                            <td>Discription</td>
                            <td>Delete</td>
                        </tr>
                    </thead>
                    <tbody>
                        {this.listTopics()}
                    </tbody>
                </Table>
                <Link to="/new-topic">
                  <Button variant="secondary" className="newTopic">Create a Topic</Button>
                </Link>
              </div>
            </Container>
            :
            <Container>
                <h1>You must be logged in and an Administrator to view this page. <Link to='/'>Return to Home</Link></h1>
            </Container>
            }
            
          </Container>
        )
    };
}

const mapSateToProps = state => {
    return {
        isLoggedIn: state.login.loggedIn,
        rank: state.login.user.rank
    }
}

export default connect(mapSateToProps)(AdminPanel);

用戶模型.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;

(忽略注釋掉的驗證字段,它是一個未完成的實驗:))

更新路線的所有其他帖子(應該是“用戶/更新/#id”)都有效。 即用戶名、密碼、email,甚至isBanned = true。 將其更改回 false 不起作用。 是的,解禁按鈕確實“起作用”,它將請求發送到后端,就像它應該做的那樣,后端將“用戶更新”發送回前端,但數據庫中的 isBanned 值保持不變。 我希望我只是忽略了一些東西,但我閱讀了所有我能解決的問題以及重新閱讀我的代碼......提前感謝您的幫助!

解決方案

如果您想嚴格使用 boolean 值,此解決方案應該可以工作,

... // Other user schema data
isBanned: String

然后在保存時使用value.toString()將 boolean 轉換為字符串,因此它保存為包含真/假值的字符串,然后在需要時使用

 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);

對我來說是最簡單也是最好的解決方案

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM