MongoDB基础之入门

2022-01-05 15:38:03 浏览数 (1)

MongoDB基础之入门

一、MONGODB简介

MongoDB由C/C 开发,是一种强大、灵活、可扩展的数据存储方式。它扩展了关系型数据库的众多有用功能,例如:辅助索引、范围查询和排序。MongoDB还内置了对MapReduce式聚合的支持,以及对地里空间索引的支持。

MongoDB容易上手,便于使用。

MongoDB是为快速开发互联网Web应用而设计的数据库系统。其数据模型和持久化策略就是为了构建高读、写吞吐量和高自动灾备伸缩性的系统。无论系统需要单个还是多个节点,MongoDB都可以提供高性能。

1、历史

2007年由10gen的创业团队开发,最终形成了MongoDB项目,10gen公司也更名为MongoDB,Inc。

MongoDB的设计目标就是极简、灵活、作为Web应用栈的一部分。

MongoDB1.0发布于2009年11月。

2、MONGODB的特点

MongoDB有以下几个特点:

  • 1.高性能。
  • 2.丰富的查询语言。
  • 3.高可用。
  • 4.水平可伸缩。
  • 5.支持多个存储引擎。

二、MONGODB入门

1、BSON文档

MongoDB将数据记录存储为BSON文档,BSON文档是JSON文档的二进制表示,但它包含的数据类型多于JSON。

BSON文档是MongoDB中数据的基本单元,非常类似于关系型数据库管理系统中的行。同时也是MongoDB的核心概念。

多个键及其关联的值有序的放置在一起便是文档。每种编程语言表示文档的方法不太一样。

1.BSON文档的特点
  • 1.文档中的键值对是有序的。通常文档中键的顺序并不重要。
  • 2.文档中的值可以是MongoDB中包含的所有数据类型。
2.BSON文档键的命名规则

BSON文档的键有以下几条命名规则:

  • 1.文档的键是字符串。
  • 2.键中不能含有(空字符),这个字符用来表示键的结尾。
  • 3.点(.)和$有特殊含义,只能在特定的环境下才能使用。
  • 4.以下划线(_)开头的键是保留键,没有做强制规定。
  • 5.键区分大小写。一个文档中不能存在重复的键。
3.文件限制

最大的BSON文档大小为16M。过大的文档,MongoDB提供了GridFS进行存储。

MongoDB在写操作之后保留文档字段的顺序,_id字段始终是文档中的第一个字段。更改字段名称可能会导致文档中字段的顺序重新排序。

2.6版本开始MongoDB主动保留文档中的字段顺序,2.6之前MongoDB没有主动保留文档中字段的顺序。

4._id

在MongoDB中,存储在集合中的每个文档都需要一个唯一的_id字段作为主键。如果插入的文档省略了该_id字段,MongoDB驱动程序会自动为该字段生成ObjectId类型作为其值。

_id字段具有以下功能:

  • 1.默认情况下,MongoDB在创建集合期间会使用_id为集合创建唯一索引。
  • 2._id字段始终是文档中的第一个字段。如果服务器收到的文档_id字段不在第一位,则服务器会将该字段移动到开头。
  • 3._id字段可以包含除阵列之外的任何BSON数据类型的值。(不要存储BSON正则表达式类型。)

_id常用的数据类型:

  • 1.使用ObjectId。
  • 2.使用自然唯一标识符。可以节省空间并避免额外的索引。
  • 3.自动递增的数字。
  • 4.在应用程序代码中生成UUID。为了更有效地存储集合和_id 索引中的UUID值,请将UUID存储为BSON BinData类型的值。
  • 5.使用驱动程序的BSON UUID工具生成UUID。请注意,驱动程序可能以不同方式实现UUID序列化和反序列化逻辑,可能会与其他驱动程序不完全兼容。

2、集合

集合就是一组文档的合集。集合类似于关系型数据库中的表。

1.无模式

集合是无模式的,也就是说一个集合里面的文档可以是各式各样的。MongoDB对此没有做强制要求,让开发者更灵活。

没有模式的控制,那么设计文档以及集合,就成为一个重点。

我们应该将同类型的文档放在一个集合中,这样可以使数据更加集中,方便管理,同时方便创建索引。

MongoDB3.2版本开始加入了更新和插入操作期间强制执行集合的文档验证规则。

2.集合命名

集合的命名有以下几点要求:

  • 1.集合名称应以下划线或字母字符开头。
  • 2.集合名不能是空字符串。
  • 3.集合名中不能包含空字符,这个字符表示集合名的结尾。
  • 4.集合名不能以“system.”开头,这是为系统集合保留的前缀。
  • 5.用户创建的集合名字不能包含$符号。

如果创建的集合中包含特殊字符,例如下划线、数字开头,那么要访问这个集合,要使用db.getCollection()方法。

集合命名空间的最大长度为120个字节。集合命名空间包含:数据库名称、点(.)分隔符和集合名称。

3.唯一标识符

MongoDB3.6中增加了一个新功能,在featureCompatibilityVersion设置为3.6,可以为每个集合分配一个不可变的UUID,这个UUID在副本集的所有成员和分片集群张总的分片中保持一致。

4.系统集合

MongoDB内部对集合的使用方式可以体现它的部分设计思想。

system.namespaces与system.indexes就属于系统集合。这两个都是标准的集合,但是MongoDB使用固定集合来做复制。

(1)system.namespaces

可以查询到当前数据库中定义的所有命名空间。

(2)system.indexes

存储了当前数据库的所有索引定义。

5.子集合

组织集合的一种惯例是使用点(.)字符分开的按命名空间划分的子集合。

3、数据库

MongoDB中多个文档组成集合,同样多个集合可以组成数据库。一个MongoDB实例可以承载多个数据库,它们之间可视为完全独立的。每个数据库都有独立的权限控制,在磁盘上,不同的数据库会放置在不同的文件中。

把数据库的名字放到集合名前面,得到的就是集合的完全限定名,称为命名空间。

命名空间的长度不得超过121字节,在实际使用当中应该小于100字节。

1.数据库命名

数据库命名分两种情况,一种是Windows系统下,一种是Linux系统下。

MongoDB中的数据库名称不区分大小写,且长度要少于64个字符。

Windows系统下:

  • 不能包含斜杠(/)、反斜杠()、点(.)、空格、双引号(")、美元符号($)、星号(*)、左尖括号(<)、右尖括号(>)、冒号(:)、竖杠(|)、问号(?)、空字符。

类Unix系统下:

  • 不能是空字符串、空格、点(.)、斜杠(/)、反斜杠()和空字符()。

注意:数据库名最终会变成文件系统里的文件名,这也就是有这些限制的原因。

2.系统中保留的数据库

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

(1)admin

此数据库是权限数据库,也就是root数据库,将一个用户添加到这个数据库,那么这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。

(2)local

这个数据库永远不会被复制,可以用来存储限于本地单台服务器的任意集合。

(3)config

当MongoDB用于分片设置时,config数据库在内部内部会使用,用于保存分片的相关信息。

4、安装

在选择版本的时候要注意:

MongoDB的稳定版本用偶数次版本号来标记,例如:1.8、2.0和2.2这些是版本是稳定版本;1.9和2.1是开发版本,不应该在生产环境中使用。

1.在Windows上安装MongoDB

参见博客:Windows下安装MongoDB

2.在Linux上安装MongoDB
(1)下载安装

官方下载地址:https://www.mongodb.com/download-center/community

可以使用浏览器或者curl工具下载安装包:

代码语言:javascript复制
curl https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.12.tgz mongo.tgz
tar –zxvf mongo.tgz

创建数据目录并授权:

代码语言:javascript复制
mkdir –p /data/db/
chow `id –u` /data/db
(2)启动服务
代码语言:javascript复制
/mongodbHome/bin/mongod

MongoDB默认使用27017端口,如果这个端口被占用,那么可以使用如下命令更改端口:

代码语言:javascript复制
mongod --port 27018

注意命令中间是两个横杠。

(3)启动命令选项
<1> --dbpath

指向存放数据文件的目录路径,默认是/data/db。每个mongod进程都需要独立的数据目录。

当mongod启动时,会在数据目录中创建mongod.lock文件,这个文件用于防止其他mongod进行使用该数据目录。如果使用同一个数据目录启动另一个MongoDB服务器,这会报错:

代码语言:javascript复制
“Unable to acquire lock for lockfilepath:/data/db/mongod.lock.”
<2> --logpath

指向日志输出文件的路径。日志默认会输出在标准输出(stdout)里。

如果对文件夹有写权限的话,系统会在文件不存在时创建它。它会将已有文件覆盖掉,清除所有原来的日志记录。如果想要保留原来的日志,还需要使用--logappend选项。

<3> --logappend

将日志输出到日志文件中的模式,其值有true,表示追加输出,false表示覆盖输出,即每次都会将原有的日志文件删除,重新创建日志文件。

<4> --port

指定MongoDB监听端口,默认使用27017。

如果要运行多个mongod进程,则需要给每个进程指定不同的端口号,如果启动mongod时端口被占用,则报错:

代码语言:javascript复制
“Address already in use for socket” 0.0.0.0:27017”
<5> --rest

该标志将开启简单REST接口,增强服务器的默认Web控制台。Web控制台的默认端口号为mongodprot 1000,MongoDB使用了27017,那么Web控制台的端口则为28017。可以使用 http://localhost:28017 来获取数据库的管理信息。

(此项功能,本人暂时没有测试出来!)

<6> --nohttpinterface

关闭管理接口,和rest是相反选项。

<7> --fork

让进程以守护进程方式运行。

<8> --config

指定启动要使用的配置文件,加载命令行未指定的额各种选项。

<9> --auth

开启安全检查。开启之后,需要做安全相应的安全验证,才能对数据库进行操作。

<10> --bindip

指定mongod绑定的IP地址。

<11> --noscripting

禁止服务端执行JavaScript代码。

(4)配置文件

以上配置信息也可以在配置文件中全部指定,创建一个新的文本文件:mongodb.conf,内容如下:

代码语言:javascript复制
dbpath=/var/local/mongodb
logpath=/var/log/mongodb.log
port=27017
rest=true
fork=true

在启动mongod时,通过以下命令来使用配置文件:

代码语言:javascript复制
mongod –f mongodb.conf

查看启动选项列表:

代码语言:javascript复制
use admin
db.runCommand({getCmdLineOpts:1})

注意:

  • mongod在没有参数的情况下或使用默认数据目录/data/db,并使用27017端口,如果数据目录不存在或者不可写,服务会启动失败。所以在启动服务之前一定要创建数据目录并确保对该目录有写权限。如果端口被占用启动也会失败。
(5)停止服务

停止MongoDB服务有两种方式:

  • 其一:查看mongod的进程号,使用kill -2 port或者kill prot。mongod收到SINGINT或者SIGTERM时,会稳妥退出。
  • 其二:使用shutdown命令停止服务,这是管理命令,需要在admin数据库下使用,shell提供了辅助函数,简化了这一过程:
代码语言:javascript复制
db.sutdownServer()

当mongod收到这两种操作的的指令时,会等到数据库当前运行的操作或者文件预分配完成,关闭所有打开的连接,将缓存的数据刷新到磁盘,最后才会停止服务。

注意:千万不要使用kill -9来强制关闭数据库,这样上述的稳妥关闭过程就不存在了,会导致数据丢失。

5、MongoDB Shell

MongoDB Shell是一个基于JavaScript的工具,用于管理数据库和操作数据。

可执行文件mongo会加载Shell并连接到指定的mongod进程。MongoDB Shell的功能和MySQL Shell差不多,主要区别在于不使用SQL,大多数命令使用的是JavaScript表达式。

MongoDB JavaScript Shell能让你玩转数据,对文档、集合以及MongoDB的特殊查询语言有切实的体验。

1.运行Shell

启动Shell的命令如下:

代码语言:javascript复制
mongo

shell会在启动时自动连接MongoDB服务器,所以在shell启动之前要保证mongod已经启动。如果启动时没有指定其他数据库,Shell会选择则名为test的默认数据库。

shell是一个功能完备的JavaScript解释器,可以运行任何JavaScript程序。也可以调用JavaScript的标准库,还可以定义和调用JavaScript函数。

例如:

代码语言:javascript复制
#进行数学运算
>x = 200
200
>x / 5;
40
#调用标准库函数
>Math.sin(Math.PI / 2);
1
>new Date(“2019/8/21”);
ISODate("2019-08-20T16:00:00Z")
# 定义并调用函数
> function factorial (n) {
... if(n<=1) return 1;
... return n* factorial(n-1);
... }
> factorial(5);
120

注意:shell中可以使用多行命令,它会检测输入的JavaScript语句是否写完。

2.MongoDB客户端

shell其实是一个独立的MongoDB客户端,开启的时候shell会连接到MongoDB服务器的test数据库,并将这个数据库了链接赋值给全局变量db,这个变量是通过shell访问MongoDB的主要入口点。

shell为了方便习惯于SQL shell的用户添加了一些语法糖,如下:

使用use命令切换或创建数据库。

代码语言:javascript复制
use tutorial

在MongoDB中创建数据库并不是必须的操作,数据库与集合只有在第一次插入文档时才会被创建。这个行为与MongoDB对数据的动态处理方式是一致的;因为不用事先定义文档的结构,单独的集合和数据库可以在运行时被创建。

db变量此时就等于tutorial:

代码语言:javascript复制
>db
tutorial
3.shell中的基本操作

在shell中操作数据会用到4个基本操作:创建、读取、更新和删除(CRUD)。

(1)创建

MongoDB对文档的操作格式如下:

代码语言:javascript复制
db.collcetion.method(操作符)

MongoDB中集合中存储的都是文档,文档需要使用JSON来表示,如下:

代码语言:javascript复制
{username:”jones”}

该文档包含一个键值对,那么下面我们将它保存到users集合中:

代码语言:javascript复制
>db.users.insert({username:”jones”})
#查看数据
> db.users.find()
{ "_id" : ObjectId("5ce51398177285a95d705d4f"), "username" : "jones" }

因为这是保存的第一个文档,所以insert()方法不仅保存了文档,而且还创建了users集合以及tutorial库,同时还给此文档添加了一个额外的键“_id”。这个字段可以认为是文档的主键。每个MongoDB文档都要求有一个_id,如果文档在创建时没有提供此字段,那么就会生成一个MongoDB对象ID并添加到文档里。这个字段全局唯一。

(2)读取

查看数据的方法是find(),如下:

代码语言:javascript复制
> db.users.find()
{ "_id" : ObjectId("5ce51398177285a95d705d4f"), "username" : "jones" }
{ "_id" : ObjectId("5ce51477177285a95d705d50"), "username" : "smith", "country" : "Canada" }

find()方法会返回集合中所有的文档,findOne()方法只会返回一条文档:

代码语言:javascript复制
> db.users.findOne();
{ "_id" : ObjectId("5ce51398177285a95d705d4f"), "username" : "jones" }

在使用find()方法时,shell自动显示最多20个匹配的文档。

(3)更新

所有更新文档的操作都要求至少有两个参数:第一个参数指明要更新的文档;第二个参数定义被选中的文档应该如何更新。

MongoDB中支持针对性更新(targeted modification),这是MongoDB独有特性中最具代表性的。这种更新操作默认只会更新一个文档。

例如:

代码语言:javascript复制
#创建一个变量
> king = {username:"LongKing",
... age:21,
... gender:"man"}
{ "username" : "LongKing", "age" : 21, "gender" : "man" }
#将变量插入到集合中
> db.users.insert(king);
WriteResult({ "nInserted" : 1 })
#更改变量
> king.address = []
[ ]
#更新文档
> db.users.update({username:"LongKing"},king)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.find();
{ "_id" : ObjectId("5ce51398177285a95d705d4f"), "username" : "jones" }
{ "_id" : ObjectId("5d5cb4bcbff45893172e233e"), "username" : "LongKing", "age" :
 21, "gender" : "man", "address" : [ ] }
# 还可以进行如下的更新操作
> jones = db.users.findOne();
{ "_id" : ObjectId("5ce51398177285a95d705d4f"), "username" : "jones" }
> jones
{ "_id" : ObjectId("5ce51398177285a95d705d4f"), "username" : "jones" }
> jones.age = 18;
18
> jones
{
        "_id" : ObjectId("5ce51398177285a95d705d4f"),
        "username" : "jones",
        "age" : 18
}
> db.users.update({username:"jones"},jones);
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.find();
{ "_id" : ObjectId("5ce51398177285a95d705d4f"), "username" : "jones", "age" : 18 }
(4)删除

remove()方法用来从数据库中永久性地删除文档。该方法接受一个可选的查询选择器,只删除那些匹配选择器的文档。如果没有提供选择器,就删除集合中的所有文档。

例如:

代码语言:javascript复制
db.users.remove({username:”jones”}) #删除名为jones的文档
db.users.remove() #清空集合

remove()方法此操作不会删除集合,它只是从集合中删除文档,哪怕是清空操作,也会保留集合。

4.shell帮助

shell本身内置了帮助文档,可以通过help命令查看。

代码语言:javascript复制
> 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                         quit the mongo shell
>

使用db.help()可以查看数据库级别的命令帮助。

集合的相关帮助通过db.collectionName.help()来查看。

想要了解函数的功能,在输入的时候不要带括号,那样就会显示函数的JavaScript源代码。

例如:

代码语言:javascript复制
db.users.update
5.shell中的注意事项

使用db.集合名的方式来访问集合一般不会有文档,但如果集合名恰好是数据库类的一个属性就有问题了。

例如:要访问version这个集合,使用db.version就不行了,因为db.version是个数据库函数。

当JavaScript只有在db中找不到指定的属性时,才会将其作为集合返回,当有属性与目标集合同名时,可以使用getCollection()函数:

代码语言:javascript复制
>db.getCollection(“version”);
test.version

所以在设计集合名时,要注意规避这些问题。

0 人点赞