MongoDB 实战教程:数据库与集合的 CRUD 操作篇

答疑·限时优惠

如果,你想让我看见你的疑问并且百分之百的回答。可以加入我的知识星球。
AI悦创·进化岛
AI悦创·进化岛

你好,我是悦创。

公众号:AI悦创

简介

MongoDB 是非关系型数据库(NoSQL)的代表之一,它具有高灵活、可水平扩展、高可用等优秀特性,并且它提供了强大又丰富的查询语句使开发者能够随心所欲地操控数据。这些也正是它受到广大开发者和企业青睐的原因。

在本场 Chat 中,会讲到如下内容:

  • NoSQL 的概念
  • 认识 MongoDB
  • 在 Ubuntu 和 macOS 上安装 MongoDB
  • 交互式接口 MongoShell 的使用
  • MongoDB 数据类型
  • 数据库和集合的 CRUD 操作

适合人群: 对 MongoDB 感兴趣的 0 基础开发者

MongoDB 是一个非关系型数据库(NoSQL)。它拥有很多优秀特性,例如高性能、高可用、支持丰富的查询语句、无需预定义数据模型和水平可伸缩等,这些特性使它受到众多开发者的青睐。

内容提要:在认识 MongoDB 之前,我们需要了解一些非关系型数据库的概念,这有助于我们更全面的认识 MongoDB。接着学习 MongoBD 的安装、交互式接口的使用和 MongoDB 的数据类型。

1. 初识 NoSQL

NoSQL 泛指非关系型数据库,该词是关系型数据库(即 SQL)的相对称呼。我们常用的关系型数据库无法满足 WEB2.0 时代的需求,在实际应用中暴露了很多难以克服的问题。NoSQL 的产生就是为了解决例如海量数据的存储、弹性可伸缩和灵活性等方面的挑战。

1.1 NoSQL 的分类

NoSQL 数据库数量很多,但可以划分为如下图所示的 4 大类:

NoSQL 四大类

每种类型都有一个我们熟知的数据库代表,例如文档型存储数据库的代表就是 MongoDB。以下列出不同类型数据库的适用场景和数据库代表:

  • 键值存储数据库:查询速度快,非常适合业务关系简单的场景。数据库代表——Redis;
  • 列存储数据库:数据以列簇形式存储,通常用来应对分布式存储的海量数据,数据库代表——HBase;
  • 文档型存储数据库:适合存储结构化、半结构化的文档和特定格式的文档。数据库代表——MongoDB;
  • 图形数据库:它使用灵活的图形模型,适合推荐系统、社交网络。数据库代表——Neo4J。

1.2 NoSQL 的范围和定义

NoSQL 数据库并没有明确的范围和定义,但它们都存在以下特征:

  • 不需要预定义模式:不需要事先定义数据模式,预定义表结构。数据中的每条记录都可能有不同的属性和格式。当插入数据时,并不需要预先定义它们的模式。
  • 无共享架构:相对于将所有数据存储的存储区域网络中的全共享架构。NoSQL往往将数据划分后存储在各个本地服务器上。因为从本地磁盘读取数据的性能往往好于通过网络传输读取数据的性能,从而提高了系统的性能。
  • 弹性可扩展:可以在系统运行的时候,动态增加或者删除结点。不需要停机维护,数据可以自动迁移。
  • 分区:相对于将数据存放于同一个节点,NoSQL 数据库需要将数据进行分区,将记录分散在多个节点上面。并且通常分区的同时还要做复制。这样既提高了并行性能,又能保证没有单点失效的问题。
  • 异步复制:和 RAID 存储系统不同的是,NoSQL 中的复制,往往是基于日志的异步复制。这样,数据就可以尽快地写入一个节点,而不会被网络传输引起迟延。缺点是并不总是能保证一致性,这样的方式在出现故障的时候,可能会丢失少量的数据。
  • BASE:相对于事务严格的ACID特性,NoSQL 数据库保证的是BASE特性。BASE是最终一致性和软事务。

归纳:NoSQL 适用于数据模型较简单、无高度的数据一致性需求,但要求高性能和灵活性的情况。

2. 安装 MongoDB

MongoDB 官网有详细的安装指引,我们只需要根据指引进行操作即可。这里以 Ubuntu 18.04 TLS 系统和 macOS 系统为例,演示如何在系统中安装 MongoDB。

2.1 在 Ubuntu 18.04 TLS 中安装 MongoDB

安装共有 5 个步骤:导入公钥,创建列表,更新库列表,安装,验证。

Ubuntu 软件包管理工具要求使用 GPG 密钥签署软件包,以确保软件包一致性和真实性,所以我们在安装前必须导入 MongoDB 的 GPG 密钥。在终端输入以下命令:

$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4

命令执行后,终端输出内容如下:

gpg: 密钥 68818C72E525xxxx:公钥“MongoDB 4.0 Release Signing Key <packaging@mongodb.com>”已导入
gpg: 合计被处理的数量:1
gpg: 已导入:1

这说明密钥添加成功。接着为 MongoDB 创建列表文件。在终端输入以下命令:

$ echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list

然后更新库列表,对应命令如下:

sudo apt-get update

待列表更新完毕后,就可以执行 MongoDB 的安装命令了。对应命令如下:

$ sudo apt-get install -y mongodb-org

命令执行后,终端输出内容如下:

完成。
正在添加用户"mongodb"到"mongodb"组...
正在将用户“mongodb”加入到“mongodb”组中
完成。
正在设置 mongodb-org (4.0.10) ...

这代表 MongoDB 已成功安装。要注意的是,apt-get 命令会在新版本可用时升级软件包。为防止意外升级,我们可以将软件包固定在当前安装的版本上。对应命令如下:

$ echo "mongodb-org hold" | sudo dpkg --set-selections
$ echo "mongodb-org-server hold" | sudo dpkg --set-selections
$ echo "mongodb-org-shell hold" | sudo dpkg --set-selections
$ echo "mongodb-org-mongos hold" | sudo dpkg --set-selections
$ echo "mongodb-org-tools hold" | sudo dpkg --set-selections

最后,使用 --version 验证 MongoDB 是否安装成功。验证命令如下:

$ mongo --version

命令执行后,终端输出内容如下:

MongoDB shell version v4.0.10
git version: c389e7f69f637f7a1ac3cc9fae843b635f20b766
OpenSSL version: OpenSSL 1.1.0g  2 Nov 2017
allocator: tcmalloc
modules: none
build environment:
    distmod: ubuntu1804
    distarch: x86_64
    target_arch: x86_64

这说明 MongoDB 已成功安装。MongoDB 安装完成后并未自动启动,启动命令如下:

$ sudo systemctl start mongod

命令执行后,如无报错信息即视为启动成功。当然,我们也可以为它设置开机启动。对应命令如下:

$ sudo systemctl enable mongod

以上就是在 Ubuntu 18.04 TLS 系统中安装 MongoDB 的过程。

2.2 在 macOS 中安装 MongoDB

在 macOS 中,我们通常使用 Homebrew 安装应用,因此我们在安装 MongoDB 前必须先安装 Homebrew。Homebrew 官方网址为:https://brew.sh/,我们按照其指引进行安装即可。在终端执行以下命令:

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

命令执行后,系统就会自动安装 Homebrew。接着我们就可以使用 brew install name 这样的命令安装其他应用了。首先,我们将 MongoDB 的包添加到 Homebrew,对应命令如下:

$ brew tap mongodb / brew

接着执行安装命令:

$ brew install mongodb-community

命令执行后,就会在系统中安装 MongoDB。安装后会创建对应的文件,例如:

  • 配置文件,路径为:/usr/local/etc/mongod.conf
  • 日志目录,路径为:/usr/local/var/log/mongodb
  • 数据目录,路径为 /usr/local/var/mongodb

MongoDB 安装完成后通常会自己启动,或者我们可以输入命令启动它。例如前台运行(进程方式)的命令如下:

$ mongod --config /usr/local/etc/mongod.conf

或者作为服务启动,对应命令如下:

$ brew services start mongodb-community

3. 深入 MongoDB

MongoDB 是一个为了便于开发和扩展而设计的文档数据库,数据库中记录的是一个类似 JSON 键值(field-value)的数据结构,例如:

{ 
   field1 : value1 ,
   field2 : value2 ,
   field3 : value3 ,
   ... 
   fieldN : valueN 
}

每一个 field 都对应着一个 value,且 value 可以包含其他文档或数组。

3.1 MongoDB 中的常见概念

相对于我们熟知的 MySQL 数据库来说,MongoDB 中的术语和概念都“令人感到新鲜”。接下来,我们将学习 MongoDB 中的数据库、集合、文档、数组和嵌入式文档等概念。

3.3.1 数据库

MongoDB 可以拥有多个数据库,每个数据库可以拥有多个集合(你可以理解为:表),每个集合可以存储多份文档,这种关系与 SQL 数据库中的“数据库、表、数据”相当。

下图描述了 MongoDB 中数据库、集合和文档的关系:

在这里插入图片描述

数据库 fotoo 中有两个集合,它们分别是 playerbooks。每个集合中都包含了许多文档,例如集合 books 中关于书籍《红楼梦》的文档,集合 player 中关于球员 James 的文档。

3.3.2 数组

MongoDB 的文档中可以存储数组,数组索引从 0 开始。数组元素的访问格式为 .。假设现在有一个这样的文档:

{
   name: "红楼梦",
   price: 125,
   tag:["经典", "名著"]
}

当我们需要访问 tag 中的第 2 个元素(即 名著) 时,访问命令为 tag.2

嵌入式文档

点访问的方式除了可以作用在数组上之外,还可以作用在嵌入式文档。其访问格式为 .。假设现在有一个这样的文档:

{
   name: "红楼梦",
   price: 125,
   tag:["经典", "名著"],
   common:{
           author: "曹雪芹",
           otherName: "石头记"
   }
}

那么当我们需要访问作者时,访问命令为 common.author。同理,访问书籍别名时,访问命令为 common.otherName

3.2 交互式接口 MongoShell

MongoShell 是 MongoDB 的交互式 JavaScript 接口。开发者可以使用它来查询和更新数据,以及执行一些其他命令。安装并启动 MongoDB 后,可以通过命令 mongo 连接到正在运行的 MongoDB 实例。当我们执行 mongo 命令后,便会进入交互式环境。连接命令为:

$ mongo

命令执行后,将会进入到 MongoDB 的交互式 Shell 中,终端命令行标识符也会从 $ 变成 >。此时我们在 Shell 中执行 show databases,将会得到如下输出:

admin   0.000GB
config  0.000GB
local   0.000GB
test    0.000GB

这些是 MongoDB 中默认存在的数据库,出现这些数据库就代表 MongoDB 启动成功,且 Shell 可用。

提示:后续所有操作都会在 MongoShell 中进行哦

在交互式环境中输入 db ,此操作将返回默认数据库 test。如果要切换数据库,可以使用 use 命令。假设我们要使用名为 admin 的数据库,那么在交互式环境中执行:

> use admin

命令执行后,交互式环境会输出 switched to db admin ,这代表我们正在使用数据库是admin 数据库。

与 MySQL 不同的是,MongoDB 允许切换到一个不存在的数据库。当我们向一个不存在的数据库存储数据时,它会自动创建一个数据库。当我们执行如下命令:

> use ancs 
> db.fabias.insert({x: 101});

就会创建一个名为 ancs 的数据库,并向名为 fabias 的集合插入内容为 {x: 105} 的文档。

3.2.1 JavaScript 语法

上面提到,MongoShell 是一个交互式 JavaScript 接口,这意味着我们可以在里面使用 JavaScript 命令。在交互式环境中输入:

> var res = 5;
> print(res);

将会得到结果为 5 的输出。

3.2.2 Tab 补全和键盘快捷键

在日常开发中,我们会用到一些 IDE 作为辅助工具,以达到加速开发进程,节省时间的目的。其中用到得最多的就是 Tab 命令补全功能,这也是每个 IDE 或者编辑器必备的功能。MongoShell 也为我们准备了 Tab 命令补全功能,当我们输入 db.fabias.in 的时候按下 Tab 键,MongoShell 会帮助我们将 insert 关键字补齐,最终得到 db.fabias.insert。它甚至可以补全数据库名称或者集合名称,假如在输入 db.fab 时按下 Tab 键,那么它就会帮我们补全之前创建的 fabias 集合,最终得到 db.fabias

如果我们要切换历史命令,可以用键盘的上下箭头进行切换。

更多快捷键可在 MongoDB 官方文档查看

3.2.3 MongoShell 常见命令

在 MongoShell 中执行 help,将得到如下输出:

> help
    db.help()                    help on db methods
    db.mycoll.help()             help on collection methods
    sh.help()                    sharding helpers
    rs.help()                    replica set helpers
    help admin                   administrative help
    help connect                 connecting to a db help
    help keys                    key shortcuts
    help misc                    misc things to know
    help mr                      mapreduce

    show dbs                     show database names
    show collections             show collections in current database
    show users                   show users in current database
    show profile                 show most recent system.profile entries with time >= 1ms
    show logs                    show the accessible logger names
    show log [name]              prints out the last segment of log in memory, 'global' is default
    use <db_name>                set current database
    db.foo.find()                list objects in collection foo
    db.foo.find( { a : 1 } )     list objects in foo where a == 1
    it                           result of the last line evaluated; use to further iterate
    DBQuery.shellBatchSize = x   set default number of items to display on shell
    exit  

这些是 MongoShell 支持的命令和对应释义。例如 show dbs 命令可以列出所有数据库的名称,show collections 命令可以列出当前数据库中的集合。更多快捷键可查阅官方文档 Command Helpers

3.2.4 退出 MongoShell

当我们需要从 MongoShell 中退出时,可以执行 quit() 命令或使用 Ctrl+c 快捷键。当然,exit 命令也是有效的。

3.3 MongoDB 数据类型

BSON 是一种二进制序列化格式,它用于存储文档并应用在 MongoDB 的 rpc 中。BSON 的规范可在 bsonspec 查看。每种 BSON 类型都有整数和字符串标识符,例如 Double 类型的整数标识符为 1,字符串标识符为 double。具体的类型和对应关系如下表所示:

数据类型 整数标识符 字符串标识符 备注
Double 1 “double”
String 2 “string”
Object 3 “object”
Array 4 “array”
Binary data 5 “binData”
Undefined 6 “undefined” 已弃用
ObjectId 7 “objectId”
Boolean 8 “bool”
Date 9 “date”
Null 10 “null”
Regular Expression 11 “regex”
DBPointer 12 “dbPointer” 已弃用
JavaScript 13 “javascript”
Symbol 14 “symbol” 已弃用
JavaScript (with scope) 15 “javascriptWithScope”
32-bit integer 16 “int”
Timestamp 17 “timestamp”
64-bit integer 18 “long”
Decimal128 19 “decimal” 3.4 版本新增
Min key -1 “minKey”
Max key 127 “maxKey”

要注意的是,部分数据类型在 4.0 中被弃用。在 MongoShell 中,数据类型可以用 typeof 查看。命令如下:

> var ss = 5;
> typeof ss;
number

这里着重介绍一下常见的数据类型,如 ObjectIdStringDateTimestamps

3.3.1 ObjectId

ObjectId 具有生成快、占用小、可排序和值唯一等特点,它的值由 12 个字节组成,其中前 4 个 字节描述的是创建的时间戳。ObjectId 的组成如下:

[Unix 纪元以来的秒数 4字节][随机值 5字节][计数器 3字节]

在 MongoDB 中,存储在集合中的每个文档都需要一个唯一的 _id 作为主键。MongoDB 会为插入的文档生成 ObjectId,如 5d14c2c54e5abe130c4a0660,但开发者也可以在文档中定义该 _id。因此,对默认生成的 _id 进行排序相当于按创建时间进行排序。

要注意的是,虽然默认生成的 ObecjtId 的值会随着时间的推移而变化,但它们不一定是按序的。这是因为 ObjectId 生成时用到的秒数以 为单位,这就造成了同一秒内创建的 ObjectId 无法排序。还有,ObjectId 在客户端生成,所以它还会受到客户端系统时间的影响。

3.3.2 字符串

BSON 字符串的编码类型是 UTF-8,这使得可以轻松地将大多数国际字符存储在 BSON 字符串中。

3.3.3 时间戳

时间戳是一个 64 位的值,它的组成如下:

[Unix 纪元以来的秒数 32位][ordinal 给定秒内操作的递增 32位]

在单个 mongod 实例中,时间戳的值始终是唯一的。如果在顶级字段中插入包含空 BOSN 的时间戳文档,MongoDB 会使用当前时间戳替换该空的时间戳。举个例子,当我们在 MongoShell 中执行以下命令时:

> var ss = new Timestamp();
> db.colls.insertOne({timestamp: ss});
> print(ss);
> db.colls.find();

MongoShell 输出内容如下:

Timestamp(0, 0)
{ "_id" : ObjectId("5d1575f96fcb85935e9cb785"), "timestamp" : Timestamp(1561687545, 1) }

可以看到,变量 ss 是一个空的 Timestamp 对象,但在文档中显示的是带有时间的 Timestamp(1561687545, 1) 对象。要注意的是,BSON 时间戳类型主要用于 MongdoDB 内部,大多数情况下的应用开发中,使用的都是 Date 类型。

日期

BOSN 的日期是一个 64 位证书,表示自 Unix 纪元(1970-01-01)以来的毫秒数。可以使用以下命令输出日期:

var dates = new Date();
datas.toStrint();
datas.getMonth();

以上就是 MongoDB 常见的数据类型,关于 MongoDB 数据类型的更多知识可查阅官方文档。

对于从未接触过 NoSQL 数据库的读者来说,MongoDB 是一个全新的事物,很多概念和操作都“很新鲜”。接下来,我们将学习数据库、集合和文档的 CURD 操作

数据库与集合的 CRUD 操作

我们在前文已经了解到了 NoSQL 的概念,演示了 MongoDB 的安装,介绍了 MongoDB 交互接口 MongoShell 的基础用法,并学习了 MongoDB 数据库、集合和文档的关系以及数据类型方面的知识。

现在我们将学习 MongoDB 数据库和集合的 CRUD(又称为增删改查) 操作。

创建数据库与集合

MongoDB 允许我们切换到一个不存在的数据库。当我们向一个不存在的数据库存储数据时,它会自动创建一个数据库,而且我们还可以向一个不存在的集合插入文档。也就是说,当我们执行文档插入时,如果数据库和集合都不存在,那么 MongoDB 就会创建对应的数据库和集合。例如向一个不存在的数据库 humen 中并不存在的集合 child 插入文档:

> use humen
> db.child.insertOne({_id: 1, name: "James", age: 5})

命令执行后,MongoDB 中就会多出一个名为 humen 的数据库,且该数据库中存在一个名为 child 的集合。我们可以使用 find() 命令查询文档内容,对应命令如下:

> db.child.find()

命令执行后,输出如下内容:

{ "_id" : 1, "name" : "James", "age" : 5 }

这说明文档也创建成功。这种直接向不存在的集合写入文档,从而创建文档的方式称为隐式创建,MongoDB 还提供了显式的集合创建方法——db.createCollection()。显式创建集合的命令如下:

> db.createCollection("players")

命令执行后,就会在当前数据库创建一个名为 players 的集合。这里使用 show tables 验证集合是否创建成功:

> show tables

命令执行后,终端会输出集合列表,而 players 也在其中,这说明显式创建集合的方法也是可行的。

约定:大部分 MongoDB 命令在执行后都会返回执行结果,例如 show tables 执行后就会输出集合列表。为了节省篇幅,减少无用的话语衔接,后续的命令执行和返回结果将出现在同一个代码块中。例如:

执行以下命令: show tables 命令执行后的输出结果为: child players

将会变成:

> show tables` `child players

更改集合名称

MongoDB 提供了 renameCollection() 方法用于更改集合名称,其语法格式如下:

{renameCollection: "<source_namespace>", to: "<target_namespace>"}

要注意的是,集合名称必须是完整的命名空间。例如将数据库 humen 中的集合 players 的名称改为 ples,对应命令为:

> db.adminCommand({renameCollection: "humen.players", to: "humen.ples"})
{ "ok" : 1 }

根据命令执行后的返回结果,就可以知道本次操作是否成功。我们使用 show tables 验证一下:

> show tables
child
ples

players 已经不见了,取而代之的是 ples

如果使用的不是完整的命名空间,而是单纯的集合名称,那么我们将会得到内容为 Invalid namespace specified 'players' 的错误提示。

至此,我们已经学会了如何更改集合的名称。

删除数据库与集合

MongoDB 提供了 drop() 方法用于删除集合。例如删除数据库 humen 中的集合 child 的命令如下:

> use humen
> db.child.drop()
true

根据命令执行后的返回结果,就可以知道本次操作是否成功:true 代表删除成功。

删除数据库的方法有两种:

  • 当数据库中没有集合的时候,数据库也会被删除;
  • 在目标数据库中使用 db.dropDatabases() 方法删除数据库;

第一种方法,也就是我们可以使用 db.dbname.drop() 方法删除掉数据库中所有的集合,这样就能够删除数据库。第二种方法,使用 use databasename 进入到目标数据库中,然后使用 db.dropDatabases() 方法删除数据库。删除数据库 humen 的命令如下:

> use humen
> db.dropDatabase()
{ "dropped" : "humen", "ok" : 1 }

命令执行执行后,数据库 humen 被删除。

查看数据库列表与集合列表

数据库与集合的查看使用的都是 show 命令,例如查看数据库列表的命令为:

> show databases
admin   0.000GB
config  0.000GB
local   0.000GB
test    0.000GB

查看集合前,需要进入到对应的数据库中。例如查看数据库 config 中的集合列表的命令为:

> use config
> show tables
system.sessions

结果显示,数据库 config 中有一个名为 system.sessions 的集合。

小结

以上就是数据库和集合的增删改查操作。细心的读者可能已经发现了,本篇并没有介绍数据库重命名的方法。这是因为 MongoDB 并未提供直接为数据库改名的方法,虽然可以使用 db.copyDatabase() 方法复制数据库,然后删除原数据库这种方式,但这在实际应用中是不可取的。你可以想象,拷贝一个庞大的数据库所耗费的时间和资源。

接下来我还会继续撰写流式聚合操作,并深入了解语句的执行效率。

在效率提升方面,数据模型也是必须要了解的知识。然后我们将深入学习能够提高数据服务可用性的复制集。接着,我们将了解 MongoDB 的水平扩展能力。最后,我们将了解 MongoDB 数据的备份与还原,并为数据服务开启访问控制。这些内容将放到如下图所示的进阶篇中。

不要忘了加入我的作者交流群哦~

AI悦创·创造不同!
AI悦创 » MongoDB 实战教程:数据库与集合的 CRUD 操作篇

1 评论

  1. 滴!访客卡!请上车的乘客系好安全带,现在是:Tue Mar 31 2020 15:44:54 GMT+0800 (中国标准时间)

Leave a Reply