学习笔记:MongoDB(尚硅谷)

介绍

  • 本文主要记录在学习尚硅谷的 MongoDB 课程时的一些笔记
  • 尚硅谷前端学科全套课程请点击这里进行下载,提取码:afyt

一、基础内容

1.分类

(1).关系型数据库

  • 关系型数据库(RDBMS)中全都是表

  • 例如:MySQL、Oracle、DB2、SQL Server

(2).非关系型数据库

  • 非关系型数据库(NoSQL、Not Only SQL)分为好多种类,主要有:

  • 键值对数据库:Redis

  • 文档数据库:MongoDB

2.简介

  • MongoDB 的数据模型是面向文档的,即类似于 JSON 的结构(又名BSON)

  • 主要概念如下:

    • 数据库(database):一个仓库,可以存放集合
    • 集合(collection):类似于数组,可以存放文档
    • 文档(document):文档数据库中的最小单位,存储和操作的内容都是文档

3.安装

  • 可以去官网下载最新版,也可以去这里下载,下载社区版即可(3.2版本之后不支持32位系统,且最新版安装无需配置 data 目录,会自动生成)

  • 配置环境变量:

    • 打开 MongoDB 安装目录下的 bin 文件夹,将该路径添加到系统的环境变量中
  • 打开 cmd 窗口,直接输入 mongo 命令即可连接到 MongoDB 数据库

  • 可通过以下命令更改默认数据库位置和端口号

1
mongod --dbpath 数据库路径 --port 端口号		// 端口号一般介于1000-65535之间

4.指令

(1).基本

  • show dbs/datebases:显示当前的所有数据库

  • use 数据库名:进入到指定的数据库中

  • db:显示当前所处的数据库

  • show collections:显示数据库中所有集合

(2).CRUD

  • 插入:

    • db.<集合名>.insert(doc):向集合中插入文档(可一个可多个)
    • db.<集合名>.insertOne(doc):向集合中插入一个文档
    • db.<集合名>.insertMany(doc):向集合中插入多个文档
  • 查询:

    • db.<集合名>.find():查询集合中的所有文档,返回的是一个数组
    • db.<集合名>.find().count():查询集合中所有文档的数量
    • db.<集合名>.find({属性:值}):查询集合中属性是指定值的文档,若需要查询指定的属性,需要使用“查询操作符”来完成查询
      • $gt:大于指定属性的值
      • $lt:小雨指定属性的值
    • db.<集合名>.findOne():查询集合中符合条件的第一个文档,返回的是一个对象
    • db.<集合名>.find().limit(10):设置显示数据的上限
    • db.<集合名>.find().skip(10).limit(10):跳过前10条数据
      • skip((页码 -1 ) * 每页显示的条数)
      • limit(每页显示的条数)
  • 修改:

    • db.<集合名>.update({查询条件},{新对象}):默认情况会使用新对象覆盖旧对象,若需要修改指定的属性,需要使用“修改操作符”来完成修改
      • $set:修改文档中的指定属性
      • $unset:删除文档中的指定属性
      • $push/$addToSet:向数组中添加一个新的元素(后者如果数组中已存在该元素,则不会添加)
      • $inc:进行自增操作
    • db.<集合名>.updateMany():同时修改多个符合条件的文档
    • db.<集合名>.updateOne():修改一个符合条件的文档
    • db.<集合名>.replaceOne():替换一个文档
  • 删除:

    • db.<集合名>.remove():删除符合条件的所有文档(默认情况下会删除多个,但第二个参数传true时只会删除一个)
    • db.<集合名>.remove({}):删除集合中的所有文档
    • db.<集合名>.deleteOne():删除符合条件的一个文档
    • db.<集合名>.deleteMany():删除符合条件的多个文档
    • db.<集合名>.drop():删除集合
    • db.dropDatabase():删除数据库
    • !注意:一般数据库中的数据都不会删除,一般会在数据中添加一个字段,来表示数据是否被删除

5.注意

  • 在 MongoDB 中当一个文档的属性值是一个文档时,这个文档为内嵌文档

  • 在 MongoDB 中支持直接通过内嵌文档的属性进行查询,如果要查询内嵌文档则可通过 . 的形式来匹配,但此时的属性名必须使用引号

二、进阶内容

1.文档之间的联系

  • 一对一

    • 例子:夫妻
    • 可以通过内嵌文档的形式来体现出一对一的关系
  • 一对多

    • 例子:父母 - 孩子、用户 - 订单、文章 - 评论、
    • 可以通过内嵌文档来映射一对多的关系
  • 多对多

    • 例子:分类 - 商品、老师 - 学生

2.排序和投影

(1).排序

  • 在使用 find() 查询文档时,默认是按照 _id 的值进行升序排序的

  • 我们可以使用 sort() 来指定文档的排序规则,且需要传递一个对象来指定排序规则

    • 1 表示升序
    • -1 表示降序
  • 当在 sort() 中输入第二个参数时,表示先以第一个参数排序,当第一个参数相等时按第二个参数排序

(2).投影

  • 当我们只想要获取某个文档中的某个字段时可以使用 投影

  • 在查询时,可以在第二个参数的位置来设置查询结果的投影

    • 1 表示显示
    • 0 表示不显示
    • 默认显示 _id

3.Mongoose

(1).简介

  • 官网:点击这里

  • Mongoose 是一个对象文档模型(ODM)库,对 Node 原生的 MongoDB 模块进一步的优化封装并提供了更多的功能

  • Mongoose 的好处:

    • 可以为文档创建一个模式结构(Schema)
    • 可以对模型中的对象/文档进行验证
    • 数据可以通过类型转换转换为对象模型
    • 可以使用中间件来应用业务逻辑挂钩
    • 比 Node 原生的 MongoDB 驱动更容易
  • Mongoose 新对象:

    • Schema(模式对象):约束数据库中的文档结构
    • Model:作为集合中的所有文档的标识,相当于数据库中的集合 Collection
    • Document:表示集合中的具体文档

(2).连接数据库

  • 在当前项目路径的终端中进行安装

1
npm i mongoose --save
  • 在当前项目中引入 Mongoose

1
const mongoose = require("mongoose");
  • 连接 MongoDB 数据库

1
2
mongoose.connect("mongodb://数据库的ip地址:端口号/数据库名", {useNewUrlParser: true, useUnifiedTopology: true});
mongoose.connect("mongodb://localhost:27017/mongoose_test");
  • 断开 MongoDB 数据库(一般不调用,连接一次后除非项目停止、服务器关闭,否则连接一般不会断开)

1
mongoose.disconnect()

!监听数据库的连接状态

  • 在 Mongoose 对象中,有一个属性叫做 connection,该对象表示的就是数据库连接,通过监视该对象的状态就可以监听数据库的连接与断开

  • 数据库连接成功的事件:

1
2
3
mongoose.connection.once("open", function (){
console.log("数据库连接成功");
})
  • 数据库连接断开的事件:

1
2
3
mongoose.connection.once("close", function (){
console.log("数据库连接断开");
})

(3).创建Schema

  • 通过创建 Schema 对象来进行

1
2
3
4
5
6
7
8
9
const Schema = mongoose.Schema;
const stuSchema = new Schema({
name: String,
age: Number,
gender: {
type: String,
default: "male"
}
})
  • 如果想要设置默认值,可以通过以下方式进行设置:

1
2
3
4
gender: {
type: String,
default: "male"
}

(4).创建Model

  • 可通过以下命令来创建 Model,参数一为要映射的集合名,参数二为创建好的 Schema 对象

  • mongoose 会自动将集合名变为复数

1
const StuModel = mongoose.model("students", stuSchema);

(5).Module的方法

1).插入文档

  • 使用以下命令来插入文档,参数一为需要插入的文档内容,参数二为回调函数

1
2
3
4
5
6
7
8
StuModel.create({
name: "孙悟空",
age: 18
}, function (err){
if(!err){
console.log("插入成功!");
}
})

2).查询文档

  • Module.find():查询所有符合条件的文档

  • Module.findOne():查询符合条件的第一个文档

  • Module.findById():根据文档id属性查询文档

  • 参数有:

    • condition:查询的条件(对象)
    • projection:投影(可以使用传统方式,也可以传入一个对象 "name age -_id" 来投影)
    • options:查询选项(skip、limit)
    • callback:回调函数,必传否则不会查询

3).修改文档

  • Module.update()

  • Module.updateMany()

  • Module.updateOne()

  • Module.replaceOne()

  • 参数有:

    • condition:查询条件
    • doc:修改后的对象
    • options:配置参数
    • callback:回调函数

4).删除文档

  • Module.remove()

  • Module.deleteOne()

  • Module.deleteMany()

  • 参数有:

    • conditions:查询条件
    • callback:回调函数

5).统计文档

  • Module.count(conditions, callback):统计文档的数量

(6).Document的方法

  • Document 是 Module 的实例,和集合中的文档一一对应

  • document.save():保存到数据库

  • document.update():修改对象

  • document.remove():删除对象

  • document.get():获取文档中的指定属性值

  • document.set():设置文档中的指定属性值

  • document.id():获取文档的 _id 属性值

  • document.toJSON():转换为一个 JSON 对象

  • document.toObject():转换为一个 Object 对象,转换之后所有的 Document 对象的方法或属性都不能使用

(7).模块化

  • 把连接数据库的代码封装到一个工具文件中,如下:

1
2
3
4
5
6
7
8
9
<-- conn_mongodb.js -->
const mongoose = require("mongoose");
mongoose.connect("mongodb://127.0.0.1:27017/mongoose_test");
mongoose.connection.once("open", function (){
console.log("数据库连接成功");
})
mongoose.connection.once("close", function (){
console.log("数据库连接关闭");
})
  • 把创建 Schema 和 Model 的代码封装到专门存放Model对象的文件夹中,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<-- student.js -->
const mongoose = require("mongoose")
const Schema = mongoose.Schema;
const stuSchema = new Schema({
name: String,
age: Number,
gender: {
type: String,
default: "male"
}
})
const StuModel = mongoose.model("student", stuSchema);
module.exports = StuModel;
  • 最后在所需的文件中直接引入这两个内容即可

1
2
3
4
5
6
<-- model.js -->
require("./tools/conn_mongodb");
const student = require("./modules/student");
student.find({}, function (err, docs){
console.log(docs);
})

三、案例分析

1.向数据库中添加20000条数据

(1).普通方法

  • 将数据库插入操作放入循环中,性能极差,耗时长

1
2
3
for(let i = 1; i <= 20000; i++){
db.numbers.insert({num:i})
}

(2).优化方法

  • 先循环将20000条数据添加到数组中,再将这个数组插入到数据库的集合中,性能好,耗时短,推荐

1
2
3
4
5
let arr = [];
for(let i = 1; i <= 20000; i++){
arr.push({num : i})
}
db.numbers.insert(arr);