抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

MongoDB基本概念

MongoDB基本概念

和传统数据库对比

不管我们学习什么数据库都应该学习其中的基础概念,在mongodb中基本的概念是文档、集合、数据库,下面我们挨个介绍,下表将帮助您更容易理解Mongo中的一些概念:

对比项 mongo 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
table joins 表连接,MongoDB不支持
primary key primary key 主键,MongoDB自动将_id字段设置为主键

通过下图实例,我们也可以更直观的了解Mongo中的一些概念:

数据逻辑层次关系:文档=>集合=>数据库\

下面我们对里面的每一个概念进行详细解释

数据库

一个mongoDB的实例可以运行多个database,database之间是完全独立的,每个database有自己的权限,每个database存储于磁盘的不同文件。

命令规范

databases的name可以是任意的UTF-8字符串。但是有以下限制

  • 空字符串””是非法的
  • 不允许出现’’,.,$,/,,\0字符
  • 建议名称都是小写
  • 不能超过64个字节
特殊数据库

有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。

  • admin:它是root级别的数据库,如果一个用户创建了admin数据库,该用户将自动集成所有数据库的权限,它可以执行一些服务器级别的命令,如列出所有数据库、关闭服务等。
  • local:该数据库将永远不能被复制,只能在单台服务器本地使用。
  • config:存储分布式部署时shard的配置信息
数据库操作
查看数据库列表

show dbs 命令可以显示所有数据的列表

1
show dbs;

显示当前数据库

执行 “db” 命令可以显示当前数据库对象或集合。

1
db

创建数据库

MongoDB 使用 use 命令创建数据库,如果数据库不存在,MongoDB 会在第一次使用该数据库时创建数据库。如果数据库已经存在则连接数据库,然后可以在该数据库进行各种操作。

1
2
3
4
show dbs;
#创建tmpdb数据库
use tmpdb;
show dbs;

注意: 在 MongoDB 中,集合只有在内容插入后才会创建! 就是说,创建集合(数据表)后要再插入一个文档(记录),集合才会真正创建。

1
2
3
4
use tmpdb;
# 在xxx的集合种插入一条数据
db.xxx.insertOne({"name":"张三"});
show dbs;

现在tmpdb数据库就显示出来了

删除数据库

可以使用db.dropDatabase()删除数据库

1
2
3
4
5
6
show dbs;
use tmpdb;
db;
#删除数据库
db.dropDatabase();
show dbs;

集合

相当于关系数据库的表,不过没有数据结构的定义。它有多个document组成。

命令规范

因为是无结构定义的,所以你可以把任何document存入一个collection里。每个collection用一个名字标识,需要注意以下几点:

  • 名字不允许是空字符串””
  • 名字不能包含\0字符,因为它表示名字的结束
  • 不能创建以system.开头的
集合操作
创建集合

可以通过db.createCollection(name,option)创建集合

参数说明:

  • name: 要创建的集合名称
  • options: 可选参数, 指定有关内存大小及索引的选项
1
2
3
4
# 创建或选择tmpdb数据库
use tmpdb;
# 在db数据库创建一个blog的集合
db.createCollection("blog");

查看集合

如果要查看已有集合,可以使用 show collectionsshow tables 命令:

1
2
show collections;
show tables;

删除集合

MongoDB 中使用 drop() 方法来删除集合db.collection.drop()

如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。

从结果中可以看出 所有的集合已被删除。

日期

表示当前距离 Unix新纪元(1970年1月1日)的毫秒数。日期类型是有符号的, 负数表示 1970 年之前的日期。

1
2
3
4
5
6
> var mydate1 = new Date() //格林尼治时间
> mydate1
ISODate("2020-02-07T07:37:04.865Z")
> typeof mydate1
object
>
1
2
3
4
5
> var mydate2 = ISODate() //格林尼治时间
> mydate2
ISODate("2020-02-07T07:37:32.998Z")
> typeof mydate2
object

这样创建的时间是日期类型,可以使用 JS 中的 Date 类型的方法。

返回一个时间类型的字符串:

1
2
3
4
5
> var mydate1str = mydate1.toString()
> mydate1str
Fri Feb 07 2020 15:37:04 GMT+0800
> typeof mydate1str
string

或者

1
2
> Date()
Fri Feb 07 2020 15:38:51 GMT+0800

文档

mongoDB的基本单位,相当于关系数据库中的行,它是一组有序的key/value键值对,使用json格式,如:{“foo” : 3, “greeting”: “Hello, world!”}。

key的命令规范

key是个UTF-8字符串,以下几点是需要注意的地方:

  • 不能包含\0字符(null字符),它用于标识key的结束
  • .和$字符在mangodb中有特殊含义,如$被用于修饰符($inc表示更新修饰符),应该考虑保留,以免被驱动解析
  • 以_开始的key也应该保留,比如_id是mangodb中的关键字
注意事项
  • 在mangodb中key是不能重复的

  • value 是弱类型,甚至可以嵌入的一个document

  • key/value键值对在mangodb中是有序的

  • mangodb是类型和大小写敏感的,如{“foo” : 3}和{“foo” : “3”}是两个不同的document,{“foo” : 3}和{“Foo” : 3}类

文档基础使用

MongoDB最主要是对文档的操作,下面我们来学习以下文档的操作

插入文档

MongoDB插入数据有多种形式,下面我们来一一学习

insert(不推荐)

插入一条或多条数据需要带有允许插入多条的参数,这个方法目前官方已经不推荐了

​ 注意:若插入的数据主键已经存在,则会抛 org.springframework.dao.DuplicateKeyException 异常,提示主键重复,不保存当前数据。

1
2
3
4
5
6
7
8
9
10
11
12
db.blog.insert({
"title" : "MongoDB 教程",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "我的博客",
"url" : "http://www.baiyp.ren",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
});

如果没有添加_id参数会自动生成_id值的,也可以自定义指定_id

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
db.blog.insert({
"_id" : "1",
"title" : "Redis 教程",
"description" : "Redis 是一个 Nosql 数据库",
"by" : "我的博客",
"url" : "http://www.baiyp.ren",
"tags" : [
"redis",
"database",
"NoSQL"
],
"likes" : 1000
});

db.blog.insert({
"_id" : "1",
"title" : "MySql 教程",
"description" : "Mysql是一个传统数据库",
"by" : "我的博客",
"url" : "http://www.baiyp.ren",
"tags" : [
"Mysql",
"database"
],
"likes" : 10000
});

如果_id重复会抛出异常

insertOne(推荐)

官方推荐的写法,向文档中写入一个文档

1
2
3
4
5
6
7
8
9
10
11
db.blog.insertOne({
"title" : "MySql 教程",
"description" : "Mysql是一个传统数据库",
"by" : "我的博客",
"url" : "http://www.baiyp.ren",
"tags" : [
"Mysql",
"database"
],
"likes" : 10000
});

这样就将数据插入到mongoDB中了

insertMany(推荐)

该语句是进行批量插入的,可以直接进行批量插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
db.blog.insertMany([{
"title" : "MySql 教程1",
"description" : "Mysql是一个传统数据库",
"by" : "我的博客",
"url" : "http://www.baiyp.ren",
"tags" : [
"Mysql",
"database"
],
"likes" : 10000
},{
"title" : "MySql 教程2",
"description" : "Mysql是一个传统数据库",
"by" : "我的博客",
"url" : "http://www.baiyp.ren",
"tags" : [
"Mysql",
"database"
],
"likes" : 10000
}]);

这样就将多个文档插入到MongoDB中了

查询文档

查询所有文档

find 方法用于更新已存在的文档,MongoDB 查询数据的语法格式如下

1
db.blog.find();

这样就将所有的数据查询出来了

格式化文档

这样看起来不太美观,可以通过pretty进行格式化

1
db.blog.find().pretty();

经过格式化这样看起来就好看多了

只返回一个文档

find();是返回所有的文档,如果想要只返回第一个文档可以使用findOne()

1
db.blog.findOne();

注意:findOne自动带有格式化效果,不需要在加上pretty方法了

等值查询

我们查询blog表中title='MySql 教程2'的数据

1
db.blog.find({"title":"MySql 教程2"}).pretty();

这样我们就将数据给查询出来了

投影

projection选择可以控制某一列是否显示,语法格式如下

find({},{"title":1})

其中如果title1则该列显示,否则不显示

1
2
3
4
5
6
#只显示title列的数据
db.blog.find({"title":"MySql 教程2"},{"title",1}).pretty();
#只显示title和description列的数据
db.blog.find({"title":"MySql 教程2"},{"title":1,"description":1}).pretty();
# 不显示 title和description列的数据
db.blog.find({"title":"MySql 教程2"},{"title":0,"description":0}).pretty();

注意在一个查询中,投影列的状态必须是一致的,如果不一致将会报错

1
2
# 显示 title 不显示description列的数据
db.blog.find({"title":"MySql 教程2"},{"title":1,"description":0}).pretty();

更新文档

update更新

update() 方法用于更新已存在的文档,更新的时候需要加上关键字 $set

1
db.blog.update({"_id":"1"},{$set:{'likes',666}})

和普通的SQL的对应关系如下

执行完成后查询,我们发现数据已经更新了

save更新

save() 方法通过传入的文档来替换已有文档,_id 主键存在就更新,不存在就插

1
2
3
4
5
6
7
8
9
10
11
12
db.blog.save({
"_id" : "1",
"title" : "MySql 传统教程教程3",
"description" : "Mysql是一个传统数据库",
"by" : "我的博客",
"url" : "http://www.baiyp.ren",
"tags" : [
"Mysql",
"database"
],
"likes" : 100000
});

如果_id不存在则进行插入操作

如果_id存在则更新数据

1
2
3
4
5
6
7
8
9
10
11
12
13
db.blog.save({
"_id" : "1",
"title" : "Redis 教程",
"description" : "Redis 是一个 Nosql 数据库",
"by" : "我的博客",
"url" : "http://www.baiyp.ren",
"tags" : [
"redis",
"database",
"NoSQL"
],
"likes" : 1000
});

删除文档

条件删除文档

remove() 方法可以删除文档

1
db.blog.remove({"_id":"1"})

这样是删除_id是1的数据

我们看到数据已经被删除了,我们可以不加条件删除多个文档

1
db.blog.remove({});

这样就删除了所有的文档

只删除第一个文档

remove({})方法可以删除所有问题,如果我们只要删除符合条件的第一个文档

准备数据

我们插入多条数据,这里用到了mongodb shell,后面我们会讲到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for(var i=0;i<10;i++){
db.blog.save({
"_id": i,
"title" : "Redis 教程",
"description" : "Redis 是一个 Nosql 数据库",
"by" : "我的博客",
"url" : "http://www.baiyp.ren",
"tags" : [
"redis",
"database",
"NoSQL"
],
"likes" : 1000
});
}

这样我们就连续插入了10条数据

remove方式删除

可以使用justOne参数,默认是true,删除所有符合条件的数据,如果是false 则只删除符合条件的第一个文档

1
db.blog.remove({},true);

这样就把第一个_id0的数据给删除了

delete删除文档

方推荐使用 deleteOne() 和 deleteMany() 方法删除文档

删除单个文档

deleteOne只会删除符合条件的第一个文档,和remove({},true)效果一致

1
db.blog.deleteOne({});

我们看到只删除了一个文档

批量删除文档

deleteMany 可以进行批量删除文档,和remove({})效果一致

1
db.blog.deleteMany({});

这样就把文档全部删除了

元数据

数据库的信息是存储在集合中。它们使用了系统的命名空间:

1
dbname.system.*

在MongoDB数据库中名字空间 <dbname>.system.* 是包含多种系统信息的特殊集合(Collection),如下:

集合命名空间 描述
dbname.system.namespaces 列出所有名字空间。
dbname.system.indexes 列出所有索引。
dbname.system.profile 包含数据库概要(profile)信息。
dbname.system.users 列出所有可访问数据库的用户。
dbname.local.sources 包含复制对端(slave)的服务器信息和状态。

对于修改系统集合中的对象有如下限制。

在插入数据,可以创建索引。但除此之外该表信息是不可变的(特殊的drop index命令将自动更新相关信息)。

是可修改的。 是可删除的。

MongoDB 数据类型

下表为MongoDB中常用的几种数据类型。

数据类型 描述
String 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。
Integer 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。
Boolean 布尔值。用于存储布尔值(真/假)。
Double 双精度浮点值。用于存储浮点值。
Min/Max keys 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。
Array 用于将数组或列表或多个值存储为一个键。
Timestamp 时间戳。记录文档修改或添加的具体时间。
Object 用于内嵌文档。
Null 用于创建空值。
Symbol 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。
Date 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。
Object ID 对象 ID。用于创建文档的 ID。
Binary Data 二进制数据。用于存储二进制数据。
Code 代码类型。用于在文档中存储 JavaScript 代码。
Regular expression 正则表达式类型。用于存储正则表达式。

下面说明下几种重要的数据类型。

ObjectId

ObjectId 类似唯一主键,可以很快的去生成和排序,包含 12 bytes,含义是:

  • 前 4 个字节表示创建 unix 时间戳,格林尼治时间 UTC 时间,比北京时间晚了 8 个小时
  • 接下来的 3 个字节是机器标识码
  • 紧接的两个字节由进程 id 组成 PID
  • 最后三个字节是随机数

MongoDB 中存储的文档必须有一个 _id 键。这个键的值可以是任何类型的,默认是个 ObjectId 对象

由于 ObjectId 中保存了创建的时间戳,所以你不需要为你的文档保存时间戳字段,你可以通过 getTimestamp 函数来获取文档的创建时间:

1
2
3
> var newObject = ObjectId()
> newObject.getTimestamp()
ISODate("2020-02-07T07:32:51Z")

ObjectId 转为字符串

1
2
> newObject.str
5e3d12a37e132b8078babb00

评论