node+mongoose设计的增删改查restful api(二)

1,174 阅读3分钟

文章主要记录如何实现使用express连接数据库,做增删改查,关联数据库,封装路由,jsonwebtoken鉴权,bcrypt登录密码加密,multer文件上传和一些请求数据的处理,开发日志记录。

1 连接mongoose数据库

app.js

const mongoose = require('mongoose');
// 连接mongoose数据库名为restful的数据库
mongoose.connect('mongodb://localhost:27017/restful', {
  useUnifiedTopology: true,
  useNewUrlParser: true
})
//可以使用promise链式语法
mongoose.Promise = global.Promise;

2 建立mongoose Model模型

app/models/product.js

const mongoose = require('mongoose');

//类似于Constructor,可以使用new一个对象
const productSchema = mongoose.Schema({
  _id: mongoose.Schema.Types.ObjectId,
  name: { type: String, required: true }, 
  price: { type: Number, required: true }
});

module.exports = mongoose.model('Product', productSchema);

3 基于product数据库模型Model进行增删改查

api/routes/products.js

const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');

//使用common.js引入Product模型
const Product = require('../models/product');

router.get('/', (req, res, next) => {
  Product.find() // 查看所有的Model数据,查找的是一个数组
    .select('name price _id') //选择特定的字段作为doc
    .exec()//使用它就可以使用.then .catch代理回调函数,解决call hell
    .then(docs => {
      const response = {  // 字段封装并返回
        count: docs.length,
        products: docs.map(doc => {//遍历文档,并返回经过处理的以下字段
          return {
            name: doc.name,
            price: doc.price,
            _id: doc._id,
            //使用request目的在于基于该字段再次请求其具体api内容
            request: {
              type: 'GET',
              url: 'http://localhost:3000/products/' + doc._id
            }
          }
        })
      };
      res.status(200).json(response)
    })
    .catch(err =>{
      console.log(err);
      res.status(500).json({
        error: err
      })
    })
})

router.post('/', (req, res, next) => {
//新增文档语法
  const product = new Product({
    _id: new mongoose.Types.ObjectId(),
    name: req.body.name,
    price: req.body.price
  });

  product
    .save()// 保存新的文档
    .then(result => {
      res.status(201).json({
        message: "created product successfully",
        createdProduct: { // 将已有的字段封装一个新的字段对象下
          name: result.name,
          price: result.price,
          _id: result._id,
          request: {
            type: 'GET',
            url: 'http://localhost:3000/products/' + result._id
          }
        }
      })
  })
  .catch(err => {
    res.status(500).json({
      error: err
    })
  })

})

router.get('/:productId', (req, res, next) => {
  const id = req.params.productId;
  Product.findById(id) // 基于_id查看该文档
    .select('name price _id')
    .exec()
    .then(doc => {
      if (doc) {
        res.status(200).json({
          product: doc,
          request: {
            type: 'GET',
            url: 'http://localhost:3000/products'
          }
        })
      } else {
        res.status(404).json({message: 'not found'});
      }
      
    })
    .catch(err => {
      res.status(500).json({error: err});
    })
})

router.patch('/:productId', (req, res, next) => {
  const id = req.params.productId;
  const updateOps = {};
  // for...of循环不会遍历对象的key,只会循环出数组的value 可以配合Object.keys()
  for (const ops of Object.keys(req.body)) {
    updateOps[ops] = req.body[ops]
  }
  // 基于_id修改该文档字段的属性值,当然是基于原有的字段名了
  Product.update({ _id: id }, { $set: updateOps }) 
    .exec()
    .then(result => {
      res.status(200).json({
        message: 'Product updated',
        request: {
          type: 'GET',
          url: 'http://localhost:3000/products/' + id
        }
      });

    })
    .catch(err => {
      console.log(err);
      res.status(500).json({
        error: err
      })
    })
})

router.delete('/:productId', (req, res, next) => {
  const id = req.params.productId;
  // 基于_id删除该文档
  Product.remove({ _id: id })
    .exec()
    .then(result => {
      res.status(200).json({
        message: 'Product deleted',
        request: {  // request 为POST该如何
          type: 'POST',
          url: 'http://localhost:3000/products',
          body: { name: 'String', price: 'Number' }
        }
      });
    })
    .catch(err => {
      console.log(err);
      res.status(500).json({
        error: err
      })
    })
})

module.exports = router;

4 建立Order数据模型,并关联Product数据模型

api/models/order.js

const mongoose = require('mongoose');

const orderSchema = mongoose.Schema({
  _id: mongoose.Schema.Types.ObjectId,
  //关联到Product集合(collection)
  product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', require: true },
  quantity: { type: Number, default: 1 }
});

module.exports = mongoose.model('Order', orderSchema);

api/routes/orders

4.1 Order路由增删改查

const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');

const Order = require('../models/order');
const Product = require('../models/product');

// Handle incoming  GET request to /orders 
// 处理连入到/orders的GET请求
router.get('/', (req, res, next) => {
  Order.find()
     // 仅选择其中三个字段显示
    .select("product quantity _id")
    // 第一个参数:将关联数据库表详细展示出来,第二个参数:为详细表中的展示的字段
    // 使用populate将不再是id,而是该数据库中的name price字段
    .populate('product', 'name price')
    .exec()
    .then(docs => {
      res.status(200).json({
        count: docs.length,
        orders: docs.map(doc => {
          return {
            _id: doc._id,
            quantity: doc.quantity,
            product: doc.product,
            request: {
              type: "GET",
              url: 'http://localhost:3000/orders/' + doc._id
            }
          }
        }),
        
      })
    })
    .catch(err => {
      res.status(500).json({
        error: err
      })
    })
})

// 关联数据库
//借助product的_id构建order数据集合,关联订单数
router.post('/', (req, res, next) => {
  Product.findById(req.body.productId)
    .then(product => {
      if (!product) {
        return res.status(404).json({
          message: 'page not found'
        })
      }
      const order = new Order({
        _id: mongoose.Types.ObjectId(),
        quantity: req.body.quantity,
        product: req.body.productId
      });
      return order.save();
    })
    .then(result => {
      res.status(201).json({
        message: 'order created',
        createdOrder: {
          _id: result._id,
          product: result.product,
          quantity: result.quantity
        },
        request: {
          type: 'GET',
          url: 'http://localhost:3000/orders/' + result._id
        }
      })
    })
    .catch(err => {
      console.log(err);
      res.status(500).json({
        error: err
      })
    })
})

router.get('/:orderId', (req, res, next) => {
  Order.findById(req.params.orderId)
    .populate('product', 'name') //关联product数据库的product name字段
    .exec()
    .then(order => {
      if(!order) {
        res.status(404).json({
          message: 'order not found'
        })
      }
      res.status(200).json({
        order: order,
        request: {
          type: 'GET',
          url: 'http://localhost:3000/orders'
        }
      })
    })
    .catch(err => {
      res.status(500).json({
        error: err
      })
    })
})


router.delete('/:orderId', (req, res, next) => {
  Order.remove({ _id: req.params.orderId })
    .exec()
    .then(result => {
      res.status(200).json({
        message: 'Order deleted',
        request: {
          type: 'POST',
          url: 'http://localhost:3000/orders',
          body: { productId: 'ID', quantity: 'Number' }
        }
      })
    })
})

module.exports = router;

当前项目目录