1、mongoDB中的collection一旦定义属性(createCollection({…})),则严格遵从定义的属性,除非定义发生改变。
mongoose的Schema对象中的属性,是你最终collection对象的属性的限制集。就是说,Schema的定义完毕后,会不容许非定义属性的加入。比如findOne()出的一个对象data,会受Schema的限制。如果age属性没被定义入Schema模型,则不容许你data.age = 22的加入。

2、首先cookie是保存在客户端的,在nodejs中操作cookie。
存储cookie

// 是response应答
res.cookie('userId', doc.userId, {
   path: '/', // 将cookie放在根域名
   maxAge: 1000 * 60 * 60, // cookie周期
})

取cookie

// 从request中获取
 req.cookies.userId

注:前端可以通过document.cookie读取cookie

3、nodejs中express提供的app.use方法,在加载路由前执行,可以做到全局拦截的效果。

// 在路由载入之前就实行拦截代码
app.use(function (req, res, next) {
  // 判断用户登录状态
  if (req.cookies.userId) {
    next() // 让程序往下走
  } else {
    // 白名单接口配置
    console.log(req.originalUrl) // 当前接口地址
    if (req.originalUrl === '/users/login' || req.originalUrl === '/users/logout' || req.originalUrl === '/goods') {
      next()
    } else {
      // json返回即中断下文执行,即拦截
      res.json({
        status: 10001,
        msg: '当前未登录',
        result: ''
      })
    }
  }
})
// 以下是各条路由

注意点:
req.originalUrl : 表示接口地址,带参数(/goods/list?name=‘killhand’&age=‘23’)
req.path : 表示接口的路径,不带参数 (/goods/list)

4、mongoose的用法很活。删除操作如下:
个人删除购物车单项操作:

router.post('/cart/del', function (req, res, next) {
  // 已全局拦截,故理论已登录
  const userId = req.cookies.userId
  const productId = req.body.productId
  // 1、查询用户购物车
  const cart = Users.findOne({userId}, function (err, doc) {
    if (err) {
      res.json({
        status: 1,
        msg: err.message,
        result: ''
      })
    } else {
      if (doc) {
        // 2、比对购物车
        doc.cartList.forEach((item, index) => {
          if (item.productId === productId) {
            doc.cartList.splice(index, 1)
          }
        })
        // 数组发生改变,save到mongoDB中
        doc.save(function (err, doc) {
          if (err) {
            res.json({
              status: 1,
              msg: err.message,
              result: ''
            })
          } else {
            if (doc) {
              res.json({
                status: 0,
                msg: '',
                result: doc.cartList
              })
            }
          }
        })
      }
    }
  })
})

大致就是1、判断用户登录态 2、根据cookie查用户表 3、比对req.body.productId和用户表productId 4、比对成功通过splice删除单项数据 5、返回数组给前端重新渲染

大佬的购物车单项删除流程如下:

router.post('/cart/del', function (req, res, next) {
  // 已全局拦截,故理论已登录
  const userId = req.cookies.userId
  const productId = req.body.productId

  //或者mongoDB的删除操作
  Users.update({userId}, {
    $pull:{
      'cartList': {
        productId
      }
    }
  }, function(err, doc) {
    if (err) {
      res.json({
        status: 1,
        msg: err.message,
        result: ''
      })
    } else {
      res.json({
        status: 0,
        msg: '',
        result: doc
      })
    }
  })
})

大致思路: 1、判断用户登录态 2、根据cookie更新用户表
其中第2步,核心是mongoDB的更新语法以mongoose语法实现+$pull
代码: Users.update({userId},{$pull:{‘cartList’:{productId: productId}}})
也就是:

Users.update({userId}, {
    $pull:{
      'cartList': {
        productId
      }
    }
  }, (err, doc)=>{此处跟回调方法})

5、mongoose的更新数据语法,其实包括了删除操作。
Users.update({多对象查询},{更新操作},()=>{回调函数}) // 这是mongoose更新操作的核心

6、==是值等于,===是绝对等于,而?相当于if判断
const str = ‘0’ // 这里str是字符串0,非数字0
str == 0 // true,'0’和0值相等
str === 0 // false,'0’和0值相等,但类型不相等
if(str) // true,'0’是非空字符串,恒为真,非0,或false
总结: 非空字符串,恒为真。而等于号的判断按情况而定。

7、脏数据:即处理不正确的数据。mongoDB建模初期容易出现。
就是在Schema原型中没有定义最终属性,而先创建的数据,但在之后Schema又引入新属性,又创建数据。
因为Schema的限制,新旧数据属性不同。故引用旧数据的时候可能出现属性undefined,需要小心。
空数据:值为空的数据。mongoDB会注销空数据
在mongoDB中,值为空的属性,将被注销,即消失。该属性便不存在,更不能调用该属性的值。所以,要注意赋值的时候,参数传递是否正确,以免发生空参传递,注销了mongoDB的属性。