102-《Nodejs开发》-数据库编程

34 阅读9分钟

目录

  • 数据库概念

  • 数据库交互

    • MongoDB
    • mongoose

一、数据库概念

1.1 数据库简介

  • 概念:数据库本身就是数据的仓库,即保存数据的地方。电脑中的数据也是通过软件来保存,不同的公司开发出了不同的数据库软件。大体上各个数据库可以分为两类:关系数据库和非关系型数据库

  • 关系型数据库

    • 指 数据库里的数据和数据之间都有一定的关联,那么称这样的数据库为关系数据库。

    • 常见关系型数据库

      • MySQL

        • 免费,适合中小型数据库。比如千万级以下的数据保存
      • SqlServer:微软开发,收费的,绑定于Windows平台。适合于中大型数据库。数据基本是超过千万级以上的。

      • oracle:sun公司开发的,收费。拥有丰富的功能,以及很好的安全性。适合中大型数据库。但环境比较复杂。

    • 关系型数据库优缺点

      • 结构统一,方便维护
      • 查询比较慢(一般关系型数据库是依次遍历的)
    • 应用

      • 一般会作为数据库保存项目的所有数据
  • 非关系型数据库

    • 概念:no sql,指的阉割版本的关系数据库。可以采用不同的格式来保存数据,有的使用对象来保存数据,有的使用字符串保存数据。

    • 特点

      • 因为设计出来就是为了更快的查询数据,所以基本只保留了管理数据的基本架构,以及对保存的数据格式各种各样。
    • 常见

      • MongoDB
      • Redis
      • H2
      • indexDB
      • ….
    • 优缺点

      • 查询极快,根据编号来查。
      • 插入(添加)比较麻烦
    • 应用

      • 一般会作为小型数据库进行保存数据(MongoDB)
      • 作为缓存数据库来使用(Redis)

二、 MongoDB

2.1 mongodb 简介

  • 概念:MongoDB是一款非关系型数据库软件。

  • 引入

    • 下载安装包并安装后进行使用:www.mongodb.com/try/downloa…
    • 打开安装界面,一路next,只不过在最后一步有个勾选的install mongodb compass去掉勾选。再进行安装。
  • 测试是否成功安装

    • 安装结束后,开始栏搜索计算机管理,点击进去之后再服务和应用程序板块,双击后选择服务,查看MongoDB服务是否已经启动,以下是正常成功启动状态。

      img

2.2 mongodb 相关概念

2.2.1 数据概念

  • mongodb可以有多个数据库。每个数据库由多个集合构成,每个集合(conlection)可以用于保存某一类的数据。比如订单集合可以保存所有的 订单数据。用户集合可以保存所有的用户数据。 每个集合都可以保存多个具体的数据(文档-document),每个文档本质上是一个对象。
  • 集合:一类数据的集合。每个集合可以保存多个数据。一般一个集合就保存同一类的数据。订单集合就保存订单数据,用户集合就保存用户数据,每个集合保存的每个数据又称为一个文档。
  • 文档:集合里保存的数据单位。本质是一个对象。
  • _id:是每次向数据库添加数据会自动生成的随机编码。这个在整个MongoDB中是唯一的,可以理解为该条数据(文档)的身份证号码。理由该身份证可以找到该数据。

2.3 使用MongoDB

  • 使用MongoDB一般有两种方式

    • 使用cmd(命令提示符)即终端操作数据库
    • 安装第三方开发的可视化工具进行操作。比如navicat(收费)

二、Mongoose 数据库交互

  • 前提:Nodejs提供了一个npm包:mongoose用于完成程序与MongoDB数据库的交互
  • 目的:学习使用mongoose链接数据库并实现和某个集合的数据交互

2.1 下载mongoose

  • 利用npm下载mongoose:项目根目录下下载mongoose

    npm i mongoose
    

2.2 链接MongoDB数据库

  • 需要在项目app.js中引入mongoose并使用其api完成数据库的链接

    const mongoose = require('mongoose');
    //1.指定连接数据库的路径 127.0.0.1
    const url = 'mongodb://localhost:27017/数据库名称';
    // 2. 去掉严格查询警告,从mongoose7之后会变为默认false,在6.x作为提示
    mongoose.set('strictQuery',false);
    //3.mongoose提供的api进行连接
    mongoose.connect(url);
    //4. 监听已连接事件,输出已连接
    mongoose.connection.on('connected',function(){
        //已连接成功后会执行的函数
        console.log('MongoDB已连接:'+url);
    });
    
    • 建议代码写在app.js头部区域,即引入routes路由文件之前。
    • 如果连接失败,可以尝试将url中的localhost切换成127.0.0.1再次尝试

2.3 引入指定集合数据到程序

  • 前提

    • 因为MongoDB数据库的一些数据类型是Nodejs不支持 的(比如ObjectId),为了保证数据库的数据能够正确的在程序中显示出来,我们需要利用Schema对象完成文档和Nodejs对象的数据类型的转换
  • 大概流程

    • 需要先基于要使用的集合先创建一个集合模型Schema对象,之后再利用该对象和要使用的集合进行关联,之后就可以使用mongoose提供的api进行数据的增删查改等操作
  • 详细流程

    • 1.在处理该数据的路由js文件中引入mongoose

      const mongoose = require('mongoose');
      
    • 2.创建Schema模型对象,完成数据库文档和Nodejs对象属性的数据类型的转换

      const userSchema = new mongoose.Schema({
          //_id是自动引入并转换
          username:String,
          password:String
      },{
          //取消_v字段生成
          versionKey:false
      })
      
    • 3.基于第二步新建的Schema对象完成和数据库指定集合的关联,关联之后会得到集合对象

      let userModel = mongoose.model("userModel",userSchema,'users')
      
      • 第一个参数:一个字符串,表示该集合在mongoose注册的集合模型名称,唯一的,不能重复注册。主要方便在多集合关联查询时使用,推荐名称为集合名Model
      • 第二个参数:要关联的模型schema对象
      • 第三个参数:要和模型schema对象关联的集合名称(数据库里的集合)
    • 4.基于第三步生成的集合对象调用相关api完成数据的增删查改操作.比如查询所有的数据

      router.get('/findAll',async function(req,res){
          let result =await userModel.find();
          console.log(result);
      })
      

2.4 集合对象的常用api

  • 常用api

    • find:查询
    • create:新建
    • updateMany:修改
    • deleteMany:删除
    • skip:跳过
    • limit:限制返回的数据个数
    • countDocuments:返回集合的数据个数

2.4.1 查询:find

  • 目的:完成各种条件的数据查询

  • 语法

    • 基本语法

      集合对象名.find(条件对象)
      
    • 查询所有

      集合对象名.find()
      
    • 带条件的查询

      
      1. 单条件查询:查询username为张三的所有数据
      集合对象名.find({username:'张三'})
      2. 多条件查询:查询username为张三并且password为zs123的所有数据
      集合对象名.find({username:'张三',password:'zs123'})
      3. 模糊查询:查询username包含三的所有数据
      集合对象名.find({
          username:{$regex:/三/,$options:"$i"},
      })
      集合对象名.find({
          username:{$regex:new RegExp("三"),$options:"$i"},
      })
      4. 任意其中一个条件满足即可。查询username为张三或李四的所有数据
      集合对象名.find({
          $or:[
              {username:"张三"},
              {username:'李四'}
          ]
      })
      

2.4.2 添加:create

  • 语法

    1. 添加一个数据
    let result = await 集合对象名.create(数据对象)
    //result拿到的就是新建的对象本身,也包含了_id
    2. 批量添加
    let result = await 集合对象名.create(对象数组)
    
    • 在添加之后可能数据库集合会多了一个_v字段,表示版本号,如果不需要,则修改集合的schema对象,详情见2.3

2.4.3 删除:deleteMany

  • 语法

    let result = await 集合对象名.deleteMany(条件对象);console.log(result.deletedCount)
    
    • result对象返回的是删除的信息,其中有一个deletedCount表示被删除数据的数量
    • deleteMany对象所需的条件对象用法参考find()

2.4.4 修改:updateMany

  • 语法

    let result = 集合对象名.updateMany(条件对象,更新对象)
    
    • 第一个参数:用于筛选满足条件的数据,也就是待修改的数据
    • 第二个参数:一个对象,用于表示需要修改的数据
    • result返回的是一个对象,里面有个属性modifiedCount表示修改的数据的数量,以此作为是否修改成功的判断条件

2.4.5 跳过:skip

  • 作用:跳过已查到数据的前面指定数量的数据

  • 语法

    let result = await 集合对象名.find(条件对象).skip(数字)
    
    • skip需要一个大于等于0 的数字,如果为负数会报错

2.4.6 限制个数:limit

  • 作用:限制查询数据的数量,可以和skip搭配使用。可以实现查询集合处于中间的部分数据

  • 语法

    let result = await 集合对象名.find(条件对象).limit(数字)
    
    • limit里的是一个大于等于0的数字,表示实际返回给前端数据的数量,相当于进行截取操作

2.4.7 文档数量:countDocuments

  • 作用:返回该集合里数据的总数量

  • 语法

    let result = await 集合对象名.countDocuments()
    

2.5 多集合关联查询

  • 前提:当一个集合中包含了其他集合的数据时,针对该集合的查询就称为多集合关联查询。默认情况下只能得到关联集合的_id.实际需要通过新api将关联_id转为具体的数据

  • 概念:需要通过修改集合Schema对象以及采用新apipopulate来实现完整的查询。

  • 大概流程

    • 修改待查询集合的Schema模型对象,将关联集合部分进行修改,修改后再查询数据时搭配populate来实现关联查询
  • 详细流程

    • 1.需要修改待查询集合的Schema模型对象代码,以movies集合为例。

      const moviesSchema = new mongoose.Schema({
          //_id是自动引入并转换
          //Array Number Boolean String 
          "actors":Array,
          "director":{
              type:mongoose.SchemaTypes.ObjectId,
              ref:"导演集合名称"
          },
          "movieType": "movieType":[{
            type:mongoose.SchemaTypes.ObjectId,
            ref:'movieTypesModel'
          }],
          //... 其他属性
      },{
          //取消_v字段生成
          versionKey:false
      })
      
      • ref属性写的是关联集合的模型名称,不是属性名,模型名称可以在关联集合的mongoose.model的第一个参数中获取
    • 2.在查询movies集合的时候,要搭配使用populate实现关联查询

      let result = await movieModel.find().populate("director").populate('movieType')
      
      • populate所需的参数是待查询集合中关联其他集合的属性名。当前因为跟导演集合管理的属性名是director,所以就写director
    • 3.查看查询效果