# 使用 Mongo 进行用户管理

在这个博客应用中,用户和博客之间是一对多的关系
我们使用 mongoose 包来定义用户模型和路由

# 创建用户模型

modules/user.js 中定义用户模型

const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
    username: {
        type: String,
        required: true,
        unique: true
    },
    name: String,
    passwordHash: String,
    blogs: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Blog' // 关联到 Blog 模型
        }
    ]
})
userSchema.set('toJSON', {
    transform: (document, returnedObject) => {
        returnedObject.id = returnedObject._id.toString()
        delete returnedObject._id
        delete returnedObject.__v
        delete returnedObject.passwordHash // 不要透露密码哈希
    }
})
const User = mongoose.model('User', userSchema) 
module.exports = User

# 创建用户路由

用户拥有一个唯一的用户名、名字以及一个密码哈希
安装 bcrypt 包生成密码散列

npm install bcrypt

controllers/users.js 中定义用户路由

const bcrypt = require('bcrypt')
const usersRouter = require('express').Router()
const User = require('../models/user') // 引入 User 模型
usersRouter.post('/', async (request, response) => {
  const { username, name, password } = request.body
  const saltRounds = 10
  const passwordHash = await bcrypt.hash(password, saltRounds) // 生成密码哈希
  const user = new User({
    username,
    name,
    passwordHash,
  })
  const savedUser = await user.save() // 保存到数据库中
  response.status(201).json(savedUser)
})
module.exports = usersRouter

app.js 中引入用户路由

const usersRouter = require('./controllers/users')
// ...
app.use('/api/users', usersRouter)

# 往错误处理中间件添加违反唯一性错误处理逻辑

const errorHandler = (error, request, response, next) => {
  if (error.name === 'CastError') {
    return response.status(400).send({ error: 'malformatted id' })
  } else if (error.name === 'ValidationError') {
    return response.status(400).json({ error: error.message })
  } else if (error.name === 'MongoServerError' && error.message.includes('E11000 duplicate key error')) { // 违反唯一性
    return response.status(400).json({ error: 'expected `username` to be unique' })
  }
  next(error)
}

# 更改 blog 的路由

controllers/blogs.js 中更改路由逻辑
使得当添加博客时,不仅添加到数据库中,而且添加到用户中

const blogsRouter = require('express').Router()
const Blog = require('../models/blog')
const User = require('../models/user')
blogsRouter.get('/', async (request, response) => {
  const blogs = await Blog.find({}).populate('user')
  response.json(blogs);
})
blogsRouter.post('/', async (request, response) => {
  if(!request.body.title || !request.body.url) {
    response.status(400).json({ error: 'title or url missing' });
    return
  }
  const body = request.body
  const user = await User.findById(body.userId); // 通过 userId 找到对应的 user
  const blog = new Blog({
    title: request.body.title,
    author: request.body.author,
    url: request.body.url,
    likes: request.body.likes || 0,
    user: user.id
  })
  const savedBlog = await blog.save(); // 先把新的 blogs 添加到 blogs 数据库中
  user.blogs = user.blogs.concat(savedBlog._id); // 更新 user 的 blogs 字段
  await user.save(); // 把更新的 user 保存到 user 数据库中
  response.status(201).json(savedBlog);
})
module.exports = blogsRouter

# Mongoose 连接查询

Mongoose 的连接查询是通过 .populate() 方法实现的
注意这里的 populate 的参数是各个数据库中需要连接的字段

blogsRouter.get('/', async (request, response) => {
  const blogs = await Blog.find({}).populate('user')
  response.json(blogs);
})
更新于 阅读次数