MongoDB学习笔记

本文最后更新于:1 年前

MongoDB 学习笔记

前言

数据库(database)

什么是数据库?

存储数据的仓库

为什么要有数据库?

首先数据是存储在内存里运行的,如果一断电的话,数据就会丢失,所以可以将数据存储到硬盘,但是硬盘没有联网,所以有了可以联网也可以存储数据的数据库。

数据库能做什么?

数据库可以存储数据,并且这些数据还可以连接网络,也就是和硬盘相比,可以不用将数据库到处带,就像是网盘。

数据库的服务器和客户端

值得注意的是数据库它也是分为服务器和客户端的

  • 服务器:保存数据的
  • 客户端:操作和存储数据的(CRUD)

数据库的分类

按照关系型分类:
  • 1、关系型数据库(MySQL、Orcal 等)
  • 2、非关系型数据库(MongoDB)

关系型和非关系型的区别:

总而言之就是:关系型的是创建表格, 非关系型是可以创建任意多个文档。

1、数据存储方式不同。
关系型和非关系型数据库的主要差异是数据存储的方式。关系型数据天然就是表格式的,因此存储在数据表的行和列中。数据表可以彼此关联协作存储,也很容易提取数据。
与其相反,非关系型数据不适合存储在数据表的行和列中,而是大块组合在一起。非关系型数据通常存储在数据集中,就像文档、键值对或者图结构。你的数据及其特性是选择数据存储和提取方式的首要影响因素。

2、扩展方式不同。
SQL 和 NoSQL 数据库最大的差别可能是在扩展方式上,要支持日益增长的需求当然要扩展。
要支持更多并发量,SQL 数据库是纵向扩展,也就是说提高处理能力,使用速度更快速的计算机,这样处理相同的数据集就更快了。
因为数据存储在关系表中,操作的性能瓶颈可能涉及很多个表,这都需要通过提高计算机性能来客服。虽然 SQL 数据库有很大扩展空间,但最终肯定会达到纵向扩展的上限。而 NoSQL 数据库是横向扩展的。
而非关系型数据存储天然就是分布式的,NoSQL 数据库的扩展可以通过给资源池添加更多普通的数据库服务器(节点)来分担负载。

3、对事务性的支持不同。
如果数据操作需要高事务性或者复杂数据查询需要控制执行计划,那么传统的 SQL 数据库从性能和稳定性方面考虑是你的最佳选择。SQL 数据库支持对事务原子性细粒度控制,并且易于回滚事务。

什么是 MongoDB?

一种数据库,而且是非关系型数据库。
MongoDB 是由 C++语言编写的,是一个基于分布式文件存储的开源数据库系统。
在高负载的情况下,添加更多的节点,可以保证服务器性能。
MongoDB 旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档

MongoDB 的优点

1、可以快速开发 web 型应用,因为灵活,不用像关系型数据库一样需要建表
2、MongoDB 存储的是文档(document),文档内存储的是类似 json 的结构,所谓 json 就是字符串数组

MongoDB 常见的命令

  • 开启服务器: net start MongoDB
  • 关闭服务器: net stop MongoDB
  • 打开客户端: mongo,在 cmd 窗口输入便可以连接上数据库

MongoDB 的数据库分类

  • 数据库(database):用来存储集合的,而且数据库也有分大小。
  • 集合(collection):集合类似于数组,用于存放文档的
  • 文档(document): 文档是 MongoDB 数据库中最小的单位,我们要操作的目标就是文档。

1
MongoDB关系: 数据库(database) > 集合(collection)> 文档(document

在 MongoDB 中不需要自己创建数据库和集合,便可以直接创建文档,其实就是在创建文档的同时,会将数据库和集合创建了。

安装配置 MongoDB

安装 MongoDB

在官网下载MongoDB,选择免费的社区服务,对应操作系统版本

推荐下载最新版本,4.0 以上版本集成了系统服务,不用自己去配置系统服务了

下载之后就直接安装,建议 D 盘

配置环境变量

打开高级系统设置找到环境变量,在用户变量的 Path 中配置环境变量,
我的是 D:\Program Files\MongoDB\Server\5.0\bin

启动 MongoDB

如果是安装的最新版 5.0 以上可以不用配置 data/db 和系统服务,因为默认配置好了,可以直接命令行启动
在安装路径下可以找到数据库,储存位置和 log

启动服务

打开 cmd 命令行输入 mongod 启动服务,有如下说明启动成功。

连接数据库

不要关闭此窗口,再开一个 cmd 命令行输入 mongo,默认端口 27017


浏览器访问 http://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
浏览器显示,数据库就链接成功

1
It looks like you are trying to access MongoDB over HTTP on the native driver port.

如果是安装的 4.0 以上的版本就不用配置系统服务,
先关闭 cmd 命令行,打开任务管理,选择 服务 找到 MongoDB。如果 MongoDB 正在启动就说明,已经配置好了开机自启,不用手动配置,也不用每次都手动启动 mongo

MongoDB 操作

基本指令

先打开 cmd 命令行,输入mongo连接数据库

显示当前所有的数据库

1
2
3
show dbs
//或者
show databases

进入到指定数据库

1
use 数据库名

在 MongoDB 中不需要自己创建数据库和集合,便可以直接创建文档,其实就是在创建文档的同时,会将数据库和集合创建了。
所以如果没有这个数据库 use 数据库名 会自动创建该数据库

查看当前所处数据库

1
db

显示当前数据库所有集合

1
show collections

数据库的 CRUD(增删改查)的操作

MongoDBCRUD官方文档
核心: 增: insert() 删: remove() 查: find() 改: update()
也有官方图形化工具 MongoDB Compass

增加

向集合中插入一个或者多个文档
1
2
3
db.<collection>.insert(document)
//<collection>表示集合名
//document表示插入的文档

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
db.piyou.insert({ name: '孙悟空', age: 28, address: '花果山' })
/*
表示向 集合名为piyou插入了文档, 文档内容是对象。
集合名是自己创建的,想用什么名称就用什么。
*/

db.piyou.insert([
{ name: '猪八戒', age: 38, address: '高老庄' },
{ name: '沙和尚', age: 45, address: '流沙河' },
])
/*
可以注意到: 传递的数据是数组,数组内部是对象,
其实对象就相当于文档,这就是插入了两个文档。
*/

当我们在向集合中插入文档时,如果没有给文档指定 _id 属性,则数据库会自动为文档添加_id,该属性用来作为文档的唯一标识。
自己也能指定_id,但是要必须保证唯一性,不建议这样做

输入指令ObjectId()

会输出一个唯一 id ObjectId("6166daec105f2c7be7b963e5")

向集合中插入一个文档
1
2
3
4
db.piyou.insertOne({ name: '唐僧', age: 18, address: '女儿国' })
/*
表示向集合名为piyou的 插入了一个文档。
*/
向集合中插入多个文档
1
2
3
4
5
6
7
db.piyou.insertMany([
{ name: '白骨精', age: 20, address: '白骨洞' },
{ name: '蜘蛛精', age: 24, address: '蜘蛛洞' },
])
/*
可以看到,用法是和insert是相差不多的。数组里面有对象,对象即是文档。
*/

insertOneinsertMany相对于insert增加了语义化

查询

1
2
3
4
5
6
db.<collection>.find();
//db.<collection>.find([{属性:值},{属性:值}]) 查询符合条件的集合

db.集合名.find(condition); 查询一个或多个文档 condition是查询条件 ,返回的是数组
db.集合名.findOne(condition); 查询一个文档,返回的是文档对象
db.集合名.findMany(condition) 查询多个文档
1
2
> db.students.find({_id:222}).name  //错误
> db.students.findOne({_id:222}).name //正确

例如

1
2
3
db.piyou.find({ age: 18 })
//这条语句表示的是查询age是18的文档。 值得注意的是,条件也是写在了对象里面,
//也是因为传入的值需要是json语句
1
2
db.集合名.find(condition).count();	使用count()来计数
db.piyou.find().count(); // 执行结果是: 6, 因为在插入那边是一共插入了6条数据

总结:

  • find()返回的是数组,数组内存放着文档,
  • findOne()返回的就是一个文档,
  • findMany()返回的也是数组内存放着文档的形式。
  • find()的返回值还可以调用 count(),
    用来获取符合条件的数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
查询操作符的使用
#比较操作符
$gt 大于
$gte 大于等于
$lt 小于
$lte 小于等于
$ne 不等于
$eq 等于的另一种写法

db.users.find({num:{$gt:200}}) #大于200
db.users.find({num:{$gt:200,$lt:300}}) #大于200小于300

$or 或者
db.users.find(
{
$or:[
{num:{$gt:300}},
{num:{$lt:200}}
]
}
) #大于300或小于200


#分页查询
db.users.find().skip(页码-1 * 每页显示的条数).limit(每页显示的条数)

db.users.find().limit(10) #前10条数据
db.users.find().skip(50).limit(10) #跳过前50条数据,即查询的是第61-70条数据,即第6页的数据


#排序
db.emp.find().sort({sal:1}) #1表示升序排列,-1表示降序排列
db.emp.find().sort({sal:1,empno:-1}) #先按照sal升序排列,如果遇到相同的sal,则按empno降序排列

#注意:skip,limit,sort可以以任意的顺序调用,最终的结果都是先调sort,再调skip,最后调limit

#5.设置查询结果的投影,即只过滤出自己想要的字段
db.emp.find({},{ename:1,_id:0}) #在匹配到的文档中只显示ename字段

修改

默认替换
1
2
3
4
db.<collection>.update(查询条件,新对象)
//update()默认条件下是使用新对象替换就对象
//在使用update()时,需要一个新的玩意加入,叫做修改操作符
//update()默认条件下只会修改一个

例如

1
2
db.piyou.update({ name: '猪八戒' }, { age: 39 })
//这样使用的话,会使用{age:18}覆盖掉{name:“猪八戒”…}这整条语句。
1
2
3
4
5
db.集合名.update(condition,newObject);		修改一个或多个文档
db.集合名.uodateOne(condition,newObject); 修改一个文档
db.集合名.updateMany(condition, newObject); 修改多个文档
condition: 查询的条件 newObject: 需要修改的语句

修改操作符
1
2
3
4
5
6
7
8
9
10
11
$set				表示需要设置指定的属性
$unset 表示需要删除指定的属性
$push 表示给数组添加一个新元素,因为文档内也会有数组,数组便会有数组元素
$addToset 表示给数组添加一个新元素,和push的区别是,如果出现同名的数组元素,则不会再添加
$gt 大于
$gte 大于等于
$lt 小于
$lte 小于等于
$or [{条件一,条件二}] 表示或的意思,符合条件一或者条件二
$inc 表示自增,用在在原来数据的基础上对数据加减,可用于加薪减薪的操作

使用修饰符修改属性
1
2
3
4
5
db.piyou.update({ name: '孙悟空' }, { $set: { age: 29 } })
/*
表示根据条件{name:"孙悟空"}, 找到了孙悟空的这个文档, 使用了$set(修改指定属性)
这个修改操作符,将age修改成了29
*/
修饰符删除指定属性
1
2
3
4
db.piyou.update({ name: '唐僧' }, { $unset: { address: 1 } })
/*
表示使用 $unset(删除指定属性), 将唐僧的address的属性值给删掉了
*/
替换一个
1
2
db.collection.replaceOne(查询条件,新对象)
//第一个参数是查找条件,第二个是替换内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
修改对应的属性,需要用到修改操作符,比如$set,$unset,$push,$addToSet
db.collectionName.update(
# 查询条件
{_id:222},
{
#修改对应的属性
$set:{
name:'kang2',
age:21
}
#删除对应的属性
$unset:{
gender:1 //这里的1可以随便改为其他的值,无影响
}

}
)

# update默认与updateOne()等效,即对于匹配到的文档只更改其中的第一个
# updateMany()可以用来更改匹配到的所有文档
db.students.updateMany(
{name:'liu'},
{
$set:{
age:21,
gender:222
}
}
)


# 向数组中添加数据
db.users.update({username:'liu'},{$push:{"hobby.movies":'movie4'}})

#如果数据已经存在,则不会添加
db.users.update({username:'liu'},{$addToSet:{"hobby.movies":'movie4'}})


# 自增自减操作符$inc
{$inc:{num:100}} #让num自增100
{$inc:{num:-100}} #让num自减100
db.emp.updateMany({sal:{$lt:1000}},{$inc:{sal:400}}) #给工资低于1000的员工增加400的工资

删除

删除一个或者多个
1
2
3
db.<collection>.remove()
//删除一个或者多个,第二个参数传递一个true,则只会删除一个
//如果只传一个空对象,则会删除全部

例如

1
2
3
4
5
db.piyou.remove({ age: 39 })
/*
表示删除了符合 age为39 这个条件的一个或多个文档。
也就是删掉了刚刚那个猪八戒的那条语句
*/

这个是真删除数据库,一般是不真删除。
一般在数据添加一个表示删除的字段 例如:{ isDel : 0 }
查询时添加这个属性 db.piyou.find({ isDel : 0 })

1
2
3
db.集合名.remove(condition)		删除符合条件的一个或多个文档
db.集合名.deleteOne(condition) 删除符合条件的一个文档
db.集合名.deleteMany(condition) 删除符合条件的多个文档
删除集合
1
db.<collection>.drop()
删除数据库
1
db.<collection>.dropDatabase()

注意数据库里的数据一般不删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 1. db.collectionName.remove()
# remove默认会删除所有匹配的文档。相当于deleteMany()
# remove可以加第二个参数,表示只删除匹配到的第一个文档。此时相当于deleteOne()
db.students.remove({name:'liu',true})

# 2. db.collectionName.deleteOne()
# 3. db.collectionName.deleteMany()
db.students.deleteOne({name:'liu'})

# 4. 删除所有数据:db.students.remove({})----性格较差,内部是在一条一条的删除文档。
# 可直接通过db.students.drop()删除整个集合来提高效率。

# 5.删除集合
db.collection.drop()

# 6.删除数据库
db.dropDatabase()

# 7.注意:删除某一个文档的属性,应该用update。 remove以及delete系列删除的是整个文档

# 8.当删除的条件为内嵌的属性时:
db.users.remove({"hobby.movies":'movie3'})
附加方法

以下方法也可以从集合中删除文档:

findOneAndDelete() 提供了一个排序选项。该选项允许删除按指定顺序排序的第一个文档。

db.collection.findAndModify()提供排序选项。该选项允许删除按指定顺序排序的第一个文档。

有关更多信息和示例,请参阅方法的各个参考页。

练习

内嵌文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
db.persons.insert([
{
name: '大大白',
age: 28,
hobby: {
music: ['new Boy', '云烟成雨', '秋酿'],
games: ['王者荣耀', '和平精英', '光遇'],
},
},
{
name: '小白',
age: 21,
hobby: {
movies: ['大话西游', '唐伯虎点秋香'],
games: ['王者荣耀', '旅行青蛙', '穿越火线'],
},
},
])

语句解释:

  • 向集合 persons 中插入一个数组,数组中有两个文档,文档内有一个 hobby 的文档,
  • 这个 hobby 文档被称作内嵌文档,然后 hobby 文档内有两个数组。

需求:查询喜欢玩 王者荣耀 的人

分析:王者荣耀是存在于 hobby 中的 games

1
2
3
4
5
db.persons.find({ 'hobby.games': '王者荣耀' })
/*
这是需要注意的知识点:如果查询的是内嵌文档可以使用 . 的方式查询,
不过需要使用引号,这是因为mongodb的文档是json的缘故吧。
*/
1
2
db.users.find({hobby.movies:'movie1'}) //错误
db.users.find({"hobby.movies":'movie1'})//此时查询的属性名必须加上引号

大量数据快速插入

需求: 插入 20000 条数据,有哪种是比较快捷的方式?

方式一:

1
2
3
4
5
6
7
8
9
for (let i = 1; i <= 20000; i++) {
db.nums.insert({ num: i })
}
db.users.find().count() //20000
/*
这是方式一,这种方式是需要调用insert语句20000次,效率会十分低下,那么可不可以,
只调用一次insert语句呢?如果可以的话,应该怎么实现呢?
可以将数据先存储起来,然后一次性加入。
*/

不推荐使用方式一,因为将会 insert 调用两千次,会消耗大量时间,影响性能

方式二:

1
2
3
4
5
6
7
8
9
const arr = []
for (let i = 1; i <= 20000; i++) {
arr.push({ num: i })
}
db.nums.insert(arr)
/*
这是将数据全部存到了数组中,随后再将数组插入,只执行了一次insert语句。
如果还有更好的想法都可以去尝试。
*/

推荐使用方式二,提前进行逻辑处理,减少原生的方法调用,加快程序运行

文档间的关系(三种)

一对一(one to one)
  • 内嵌文档
  • 夫妻关系
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
db.wife.insert([
{
name: '黄蓉',
age: 26,
handsband: {
name: '郭靖',
age: 38,
},
},
{
name: '小兰',
age: 16,
handsband: {
name: '新一',
age: 16,
},
},
])
/*
可以看到一个妻子是对应一个丈夫的,这是使用内嵌文档来实现的。
*/
一对多(one to many)
  • 父母 - 孩子
  • 文章 - 评论

内嵌文档也可以实现,就是一个文档内嵌多个文档,不过比较繁琐
用户一个文档,订单一个文档,在使用的时候再一一对应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 第一句是创建了两个用户, 分别是花木兰和诸葛亮
db.users.insert([{ name: '花木兰' }, { name: '诸葛亮' }])
// 这一句是查询用户内容, 这是需要知道用户的_id,从而在第三句加入
db.users.find()
// 这是生成了一个订单,并且user_id存储的是花木兰的id
db.orders.insert({
list_name: ['配马', '鞍鞯'],
user_id: ObjectId('61374eac77393663e2de9bd3'),
})
// 再生成了一个订单,并且user_id存储的是花木兰的id
db.orders.insert({
list_name: ['蜜糖', '男装'],
user_id: ObjectId('61374eac77393663e2de9bd3'),
})
// 在users里查找到 花木兰 这个用户的id,并将其存储起来
let userId = db.users.findOne({ name: '花木兰' })._id
// 使用id来查找
db.orders.find({ user_id: userId })
多对多(many to many)
  • 学生 - 老师
  • 商品 - 分类

可以使用内嵌文档的形式完成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
db.teas.insert([{ name: '诸葛亮' }, { name: '龟仙人' }, { name: '唐僧' }])
db.teas.find()
db.stus.insert([
{
name: '孙悟空',
// 插入的是 龟仙人和唐僧的id
teas_id: [
ObjectId('6137552877393663e2de9bdb'),
ObjectId('6137552877393663e2de9bdc'),
],
},
{
name: '刘禅',
// 插入的是 诸葛亮和龟仙人的id
teas_id: [
ObjectId('6137552877393663e2de9bda'),
ObjectId('6137552877393663e2de9bdb'),
],
},
])

db.stus.find()

投影(就是限制条件,显示效果)

首先先创建一个集合:

1
2
3
4
5
6
7
8
9
10
11
12
db.staff.insert([
{ name: '小白', age: 18, salary: 3000 },
{ name: '大白', age: 19, salary: 3500 },
{ name: '熊大', age: 23, salary: 3200 },
{ name: '熊二', age: 22, salary: 3100 },
{ name: '光头强', age: 27, salary: 3400 },
{ name: '小鲤鱼', age: 17, salary: 1500 },
{ name: '奥特曼', age: 39, salary: 4500 },
])
/*
这样创建的是一个列表集合。
*/
需求一:按照薪资排列,可以使用 sort()方法
1
2
3
sort(condition)
sort({salary: 1})表示按照薪资升序排列
sort({salary: -1})表示按照薪资降序排列

一个条件查询

1
db.staff.find().sort({ salary: 1 })

按照薪资升序查询结果

多条件查询

1
2
3
4
5
db.staff.find().sort({ salary: 1, age: -1 })
/*
这句的含义是按照薪资升序排序,如果出现了相同的薪资的人,
则按照年龄降序排序。
*/
分页查询

limit() 限制 和 skip() 跳过, 这两个方法经常可以一起使用,从而用来翻页。
而且这两个方法是可以不分先后的。

1
2
3
4
db.staff.find().limit(2).skip(5)
/*
表示跳过前面5个数据,显示第七八个。可以理解为5个为一页,显示第二页的2个数据
*/
投影配置

在查询时可以在 find()中的第二个参数的位置传入 投影,
{name: 1, _id: 0}: 表示 1 显示 name 属性,0 不显示_id 属性。

1
2
3
4
db.staff.find({}, { name: 1, _id: 0, salary: 1 })
/*
这句的含义是只显示 name和salary属性,不显示 _id属性
*/

Mongoose

什么是 Mongose

一般我们不会直接用MongoDB的函数来操作MongoDB数据库 ,
而Mongose就是一套操作MongoDB数据库的接口。
简而言之就是:mongoose也可以操作mongodb数据库,而且它来操作数据库会有更多好处

Mongoose 优点

可以为 mongodb 的文档创建一个模式结构(Schema),说白了就是一个约束的条件
比原生的 Node 相比更容易操作 mongodb 数据库,也就是更方便
可以使用中间件和其他的应用业务挂钩,可以和其他的应用结合使用
数据可以通过类型转换转换成对象模型,也就是有方法可以使用。

Mongoose 的三个新对象

Schema(模式对象)

定义了约束 mongodb 的文档结构的条件

Model

相当于 mongodb 中的 collection(集合)

Document

document 表示集合中的具体文档

值得注意的是这三个都是对象,是对象的话则有它们对应的方法和属性。

vscode 使用 mongoose 来操作数据库

当需要在 webstorm 或 vscode 时编写 mongoose 时,需要先将 mongoose 模块引入。步骤如下:
使用 Mongoose:

下载安装

在终端输入命令行:

1
npm i mongoose --save

步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1、导入mongoose模块
const mongoose = require('mongoose');
2、连接数据库并且监听
mongoose.connect("mongodb://数据库ip地址:端口/数据库名称");
mongoose.connection.once("open", (err)+>{});
3、创建Schema约束条件
const Schema = mongoose.Schema; 将Schema重命名
const schema约束条件 = new Schema(约束的内容);
4、创建Model
const 模型Model = mongoose.model('mongodb的集合名', schema约束条件);
5、插入文档
使用 模型Model,插入文档
模型model.create(文档document);

具体步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 1、引入 mongoose 模块
const mongoose = require('mongoose')

// 2、连接数据库 27017是默认端口号,可以省略不写, ppxia是需要连接的数据库
mongoose.connect('mongodb://127.0.0.1:27017/ppxia')

// 2.1、这是对数据库的监听,而且是使用once, 只监听一次就行了
mongoose.connection.once('open', (err) => {
if (!err) {
console.log('数据库已连接...')
}
})

mongoose.connection.once('close', (err) => {
if (!err) {
console.log('数据库已断开!!!')
}
})

// 3、重命名,简化操作
const Schema = mongoose.Schema

// 3.1、创建了约束条件:type是类型,default是默认是女,如果是女的话则不用写性别这个属性值了。
const stuSch = new Schema({
name: String,
age: Number,
gender: {
type: String,
default: '女',
},
address: String,
})

// 4、创建了 模型, 数据库中的集合名是 stuSch(会自动加s), 第二个参数是标准,即是约束条件: stuSch
const stuModel = mongoose.model('stuSch', stuSch)

// 5、使用模型创建对象, 当想创建多个的时候,可以使用数组里面存储对象的方式
stuModel.create(
{
name: '西施',
age: 18,
address: '王者峡谷',
},
(err) => {
console.log('文档创建成功~')
}
)

如果出现这种报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
E:\web\MongoDB-test\mongoose-test\node_modules\whatwg-url\dist\encoding.js:2
const utf8Encoder = new TextEncoder();
^

ReferenceError: TextEncoder is not defined
at Object.<anonymous> (E:\web\MongoDB-test\mongoose-test\node_modules\whatwg-url\dist\encoding.js:2:21)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (internal/modules/cjs/helpers.js:22:18)
at Object.<anonymous> (E:\web\MongoDB-test\mongoose-test\node_modules\whatwg-url\dist\url-state-machine.js:5:34)
PS E:\web\MongoDB-test\mongoose-test> node helloMongoose.js
(node:4888) UnhandledPromiseRejectionWarning: MongoParseError: Invalid connection string "mongoose://127.0.0.1/mongoose_test"
at new ConnectionString (E:\web\MongoDB-test\mongoose-test\node_modules\mongodb-connection-string-url\lib\index.js:66:19)
at Object.parseOptions (E:\web\MongoDB-test\mongoose-test\node_modules\mongodb\lib\connection_string.js:210:17)
at new MongoClient (E:\web\MongoDB-test\mongoose-test\node_modules\mongodb\lib\mongo_client.js:62:46)
at Promise (E:\web\MongoDB-test\mongoose-test\node_modules\mongoose\lib\connection.js:779:16)
at new Promise (<anonymous>)
at NativeConnection.Connection.openUri (E:\web\MongoDB-test\mongoose-test\node_modules\mongoose\lib\connection.js:776:19)
at _mongoose._promiseOrCallback.cb (E:\web\MongoDB-test\mongoose-test\node_modules\mongoose\lib\index.js:330:10)
at Promise (E:\web\MongoDB-test\mongoose-test\node_modules\mongoose\lib\helpers\promiseOrCallback.js:32:5)
at new Promise (<anonymous>)
at promiseOrCallback (E:\web\MongoDB-test\mongoose-test\node_modules\mongoose\lib\helpers\promiseOrCallback.js:31:10)
(node:4888) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:4888) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

打开文件 \node_modules\whatwg-url\dist\encoding.js 替换以下代码

1
2
3
4
5
6
7
8
9
10

// "use strict";
// const utf8Encoder = new TextEncoder();
// const utf8Decoder = new TextDecoder("utf-8", { ignoreBOM: true });

替换成
;('use strict')
var util = require('util')
const utf8Encoder = new util.TextEncoder()
const utf8Decoder = new util.TextEncoder('utf-8', { ignoreBOM: true })

连接数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 1.引入mongoose
const mongooes = require('mongoose')
// 2.连接mongodb数据库
mongooes.connect('mongodb://localhost/users', {
useNewUrlParser: true,
useUnifiedTopology: true,
})

// 3.监听mongodb数据库的连接状态
// 绑定数据库连接成功事件
mongooes.connection.once('open', function () {
console.log('连接成功')
})
// 绑定数据库连接失败事件
mongooes.connection.once('close', function () {
console.log('数据库连接已经断开')
})

// 4.断开数据库连接(一般不用)
//mongooes.disconnect();

创建模式对象和模型对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 重命名,简化操作
const Schema = mongoose.Schema

//创建了约束条件:type是类型,default是默认是女,如果是女的话则不用写性别这个属性值了。
const stuSch = new Schema({
name: String,
age: Number,
gender: {
type: String,
default: '女',
},
address: String,
})

//创建了 模型, 数据库中的集合名是 stuSch(会自动加s), 第二个参数是标准,即是约束条件: stuSch
//第一个参数表示创建的集合的名称,第二个参数表示利用的模式对象
const stuModel = mongoose.model('stuSch', stuSch)

利用 Model(模型)对象进行增删查改操作:

添加操作:
1
2
3
4
5
6
Model.create(doc,[callback]);			创建一个或多个对象
Model.createOne(doc, [callback]); 创建一个对象
Model.createMany(doc, [callback]); 创建多个对象
#doc是需要插入的文档
#callback(err) 是回调函数,可以用来提示是否创建成功了

1
2
3
4
5
6
7
8
9
10
11
// 使用模型创建对象, 当想创建多个的时候,可以使用数组里面存储对象的方式
stuModel.create(
{
name: '西施',
age: 18,
address: '王者峡谷',
},
(err) => {
console.log('文档创建成功~')
}
)
查询操作:
1
2
3
4
5
6
7
8
9
10
11
Model.find(condition, 投影, [options], [callback]);	 	查询一个或多个文档
# 返回的是数组
Model.findById(id, 投影, [callback]); 根据id查询一个文档
Model.findMany(condition, 投影. [callback]); 查询多个文档
Model.findOne(condition, [projection], [options], [callback]); 查询一个文档
# condition 查询条件
# 投影/ projection: 投影,也就是 查询条件,有两种方式
# {name: 1, _id:0}: 1是显示,0是不显示 "name -_id"显示name, 不显示 _id
# options: 查询的选项, skip是跳过,limit是限制 {skip: 3, limit:3}
# callback: 回调函数,有两个参数(err, doc) err是错误类型, doc是文档。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
stuModel.find({}, (err, doc) => {
if (!err) {
console.log(doc)
}
})
stuModel.findById('6137839348ee37e25b1c1c74', (err, doc) => {
if (!err) {
console.log(doc)
}
})
stuModel.findOne({ name: '西施' }, 'name -_id', (err, doc) => {
if (!err) {
console.log(doc)
}
})
修改操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Model.updateMany(condition, doc, [options], [callback]);
Model.updateOne(condition, doc, [options], callback);
## Model.update() 已经不适用了
# condition 修改的条件
# doc 修改后的内容/需要修改的内容

需要配合修改操作符来使用:
$set 表示需要设置指定的属性
$unset 表示需要删除指定的属性
$push 表示给数组添加一个新元素,因为文档内也会有数组,数组便会有数组元素
$addToset 表示给数组添加一个新元素,和push的区别是,如果出现同名的数组元素,则不会再添加
$gt 大于
$gte 大于等于
$lt 小于
$lte 小于等于
$or [{条件一,条件二}] 表示或的意思,符合条件一或者条件二
$inc 表示自增,用在在原来数据的基础上对数据加减,可用于加薪减薪的操作

1
2
3
4
5
6
7
8
9
10
11
stuModel.updateOne({ name: '西施' }, { $set: { address: '北京' } }, (err) => {
if (!err) {
console.log('修改成功~')
}
})

stuModel.find({}, (err, doc) => {
if (!err) {
console.log(doc)
}
})
删除操作
1
2
3
4
5
Model.remove(condition, [callback]);
Model.deleteOne(condition, [callback]);
Model.deleteMany(condition, [callback]);
# condition 条件

查看个数
1
2
Model.count(condition, [callback])
获取当前这个集合的符合条件的文档数量

Document(文档)的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
document.save([options], [callback])
document.update([options], [callback])
collection.update不推荐使用。改用updateOne、updateMany或bulkWrite。
doc.get(name)
获取指定属性值
doc.get("name") === doc.name
doc.set("name", "猪猪") === doc.name = "猪猪"
doc.id
属性, 获取id
doc.toJSON()
- 转换成 JSON
doc.toObject()
将doc对象 转换成 普通JS对象, 转换后, 所有doc的属性和方法都不能使用了
--这样就可以将 address给删掉了, 表面上删掉了, 数据库中没有删除
doc = doc.toObject;
delete doc.address;
console.log(doc);

模块化处理:

  • 1.单独创建一个数据库连接文件\tools\conn_mongo.js
1
2
3
4
5
6
7
8
const mongooes = require('mongoose')
mongooes.connect('mongodb://localhost/mongooes_test', {
useNewUrlParser: true,
useUnifiedTopology: true,
})
mongooes.connection.once('open', function () {
console.log('连接成功')
})
  • 2.为每一个集合创建一个模型对象文件\models\userModel.js
1
2
3
4
5
6
7
8
9
10
11
12
13
const mongooes = require('mongoose')
const Schema = mongooes.Schema
const userSchema = new Schema({
user_id: String,
name: String,
age: Number,
gender: {
type: Number,
default: 0,
},
})
const UserModel = mongooes.model('user', userSchema)
module.exports = UserModel
  • 3.在最终的文件 index.js 中引入数据库连接文件和创建模型的文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const mongooes = require('./dbconncet')
const PostModel = require('./models/postModel')

//第一次创建之后才有数据
// PostModel.create(
// {
// user_id: 123,
// name: '小明',
// age: 18,
// },
// (err, data) => {
// if (err) {
// console.log('文档创建成功~~~')
// }
// }
// )

PostModel.findOne({}, function (err, data) {
if (!err) {
console.log(data)
}
})