第一部分 基础篇 第四章 MongoDB快速入门

声明:该文章主要来自《MongoDB实战》一书内容,主要想通过该书学习MongoDB的相应知识,加深理解,故写在自己的博文当中,作为记录,在最后的章节中,会有一个自己集合MongoDB数据库应用的JavaEE的web应用。

MongoDB shell是MongoDB自带的交互式JavaScript shell,用来对MongoDB进行操作和管理的交互式环境。

使用./mongo --help可以查看相关连接参数,下面将从常见的操作,如插入、查询、修改、删除等几个方面阐述MongoDB shell的用法。

1.1、启动数据库

MongoDB安装、配置完后,必须先启动它,然后才能使用它,怎么启动它呢?下面分别展示了3种方式启动实例。

1.1.1、命令行方式启动

MongoDB默认存储数据目录为/data/db/(或者C:\data\db),默认端口为27017,默认HTTP端口为28017,当然你也可以修改成不同目录,只需要指定dbpath参数:

./mongod --dbpath=/var/mongodb/data/ --logpath /var/mongodb/logs/log.log -fork

说明:--fork表示后台进程启动。

1.1.2、配置文件方式启动

如果是一个专业的DBA,那么实例启动时会添加很多的参数以便使系统运行的非常稳定,这样就可以会在启动时在mongod后面加一长串的参数,看起来非常混乱而且不好管理和维护,那么有什么办法让这些参数有条理呢?MongoDB也支持同mysql一样的读取启动配置文件的方式来启动数据库,配置文件的内容如下:

[root@localhost bin]# vi /etc/mongodb.cnf

dbpath=/var/mongodb/data/

启动时加上-f参数,并指向配置文件即可

[root@localhost bin]# ./mongod -f /etc/mongodb.cnf

1.1.3、Daemon方式启动

大家可以注意到上面的两种方式都在前台启动MongDB进程,但当启动MongoDB进程的session窗口不小心关闭时,MongoDB进程也将随之停止,这样无疑是非常不安全的,幸好MongoDB提供了一种后台Daemon方式启动的选择,只需要加上一个--fork参数即可,这就使得我们可以更方便的操作数据库的启动,但如果用到了--fork参数就必须也启动--logpath参数,这是强制的。

./mongod --dbpath=/var/mongodb/data/ --logpath /var/mongodb/logs/log.log -fork

没有--logpath参数,则会提示:--fork has to be used with --logpath

1.1.4、MongoDB参数说明

最简单的、通过执行mongod即可启动MongoDB数据库服务,mongod支持很多的参数,但都有默认值,其中最重要的是需要制定数据文件路径,或者确保默认的/data/db/存在并且具有访问权限,否则启动后会自动关闭服务,那也就是说,只要确保dbpath就可以启动MongoDB服务了。

mongod的主要参数有:

  • dbpath:数据文件存放路径,每个数据库会在启动创建一个子目录,用于防止同一个实例多次运行的mongod.lock也保存在此目录中。
  • logpath:错误日志文件。
  • logappend:错误日志采用追加模式(默认是覆写模式)
  • bind_ip:对外服务的绑定ip,一般设置为空,以及绑定在本机所有可用ip上,如有需要可以单独制定。
  • port:对外服务端口,web管理端口在这个port的基础上+1000。
  • fork:以后台Daemon形式运行服务。
  • journal:开启日志功能,通过保存操作日志类降低单机故障的恢复时间,在1.8版本后正式加入,取代在1.7.5版本中的dur参数。
  • syncdelay:系统同步刷新磁盘的时间,单位为秒,默认是60秒。
  • directoryperdb:每个db存放在单独的目录中,建议设置该参数,域MySQL的独立表空间类似。
  • maxConns:最大连接数。
  • repairpath:执行repair时的临时目录,在如果没有开启joural,异常down机后重启,必须执行repair操作。
在源代码中,mongod的参数分为一般参数,windows参数,replication参数,replica set参数,以及隐含参数,上面列举了的都是一般参数,如果要配置replication、replica set等,还需要设置对应的参数,这里先不展开,后续会有专门的章节来讲述,执行mongod --help可以看到对大多数参数的解释,但又一些隐含参数,则只能通过看带来获得(见db.cpppo::options_description hidden_options("Hidden options");),隐含参数一般要么是还在开发中,要么是准备废弃,因此在生产环境中不建议使用。
可能你已经注意到,mongod的参数中,没有设置内存大小相关的参数,是的,MongoDB使用os mmap机制来缓存数据文件数据,自身目前不提供缓存机制,这样好处是代码简单,mmap在数据量不超过内存时效率很高,但是数据超过系统可用内存后,则写入的性能可能不太稳定,容易出现大起大落 ,不过在最新的1.8版本中,这个情况相对以前的版本已经有了一定程度的改善。
这么多参数,全面写在命令行中则容易杂乱而不好管理,因此mongod支持将参数写入到一个配置文本文件中,然后通过config参数来引用此配置文件:
./mongod --config /etc/mongo.cnf

1.2、停止数据库
MongoDB提供的停止数据库命令也非常丰富,如果Control-C、发送shutdownServer()指定以及发送Unix系统中断信号等。
1.2.1、Control-C
如果处理连接状态,那么直接可以通过Control-C的方式去停止MongoDB实例,具体如下:
[root@localhost bin]# ./mongo
MongoDB shell version: 2.6.6
connecting to: test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
        http://docs.mongodb.org/
Questions? Try the support group
        http://groups.google.com/group/mongodb-user
> ^C
bye
[root@localhost bin]# 
1.2.2、shutdownServer()指令
如果处理连接状态,那么直接可以通过admin库中发送db.shutdownServer()指令去停止MongoDB实例,具体如下:
[root@localhost bin]# ./mongo
MongoDB shell version: 2.6.6
connecting to: test
> use admin
switched to db admin
> db.shutdownServer()
2015-01-04T10:23:44.506+0800 DBClientCursor::init call() failed
server should be down...
2015-01-04T10:23:44.519+0800 trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed
2015-01-04T10:23:44.521+0800 warning: Failed to connect to 127.0.0.1:27017, reason: errno:111 Connection refused
2015-01-04T10:23:44.521+0800 reconnect 127.0.0.1:27017 (127.0.0.1) failed failed couldn‘t connect to server 127.0.0.1:27017 (127.0.0.1), connection attempt failed

1.2.3、Unix系统指令
在找到实例的进程后,可能通过发送kill -2 PID或者kill -15 PID来停止进程,具体如下:
[root@localhost bin]# ps aux|grep mongod
root      2676  1.4  3.0 467208 30668 ?        Sl   10:24   0:00 ./mongod --dbpath=/var/mongodb/data/ --logpath /var/mongodb/logs/log.log -fork
root      2695  0.0  0.0 103236   864 pts/1    S+   10:24   0:00 grep mongod
注意:不要使用kill -9 PID来杀死MongoDB进程,这样可以会导致MongoDB的数据损坏。
[root@localhost bin]# kill -2 2676

1.3、连接数据库
现在我们就可以使用自带的MongoDB shell工具来操作数据库了,我们也可以使用各种编程语言的驱动来使用MongDB,但自带的MongoDB shell工具可以方便我们管理数据库,新打开一个Session输入:/usr/local/mongodb/bin/mongo,如果出现下面提示,那么你就说明连接上数据库了,可以进行操作了。
[root@localhost bin]# ./mongo
MongoDB shell version: 2.6.6
connecting to: test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
        http://docs.mongodb.org/
Questions? Try the support group
        http://groups.google.com/group/mongodb-user

默认shell连接的是本机的localhost上面的test库,"connection to:"这个会显示你正在使用的数据库名称,想换数据库的话可以用use mydb来实现。

1.4、插入记录
下面我们来建立一个test的集合并写入一些数据,建立两个对象j和t,并保存到集合中区,在例子里">"来表示用shell输入提示符。
> a={name:"mongo"}
{ "name" : "mongo" }
> b={x:4}
{ "x" : 4 }
> db.xuz.save(a)
WriteResult({ "nInserted" : 1 })
> db.xuz.save(b)
WriteResult({ "nInserted" : 1 })
> db.xuz.find();
{ "_id" : ObjectId("54a8a4ff2db3e1b27d0e5203"), "name" : "mongo" }
{ "_id" : ObjectId("54a8a5042db3e1b27d0e5204"), "x" : 4 }
说明:
  • 不需要预先创建一个集合,在第一次插入数据时会自动创建。
  • 在文档中其实可以存储任何结构的数据,当然在实际应用我们存储的还是相同类型文档的集合,这个特性其实可以在应用里很灵活,你不需要类似alter table语句来修改你的数据结构。
  • 每次插入数据时候集合中会有一个ID,名字叫_id。
下面再添加一些数据:
> for(var i=1;i<=50;i++) db.xuz.save({x:5,j:i});
WriteResult({ "nInserted" : 1 })
> db.xuz.find();
{ "_id" : ObjectId("54a8a4ff2db3e1b27d0e5203"), "name" : "mongo" }
{ "_id" : ObjectId("54a8a5042db3e1b27d0e5204"), "x" : 4 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2466"), "x" : 5, "j" : 1 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2467"), "x" : 5, "j" : 2 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2468"), "x" : 5, "j" : 3 }
{ "_id" : ObjectId("54a8a5a427681683ca2c2469"), "x" : 5, "j" : 4 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246a"), "x" : 5, "j" : 5 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246b"), "x" : 5, "j" : 6 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246c"), "x" : 5, "j" : 7 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246d"), "x" : 5, "j" : 8 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246e"), "x" : 5, "j" : 9 }
{ "_id" : ObjectId("54a8a5a427681683ca2c246f"), "x" : 5, "j" : 10 }
{ "_id" : ObjectId("54a8a620e708df7187eb2dd8"), "x" : 5, "j" : 1 }
{ "_id" : ObjectId("54a8a620e708df7187eb2dd9"), "x" : 5, "j" : 2 }
{ "_id" : ObjectId("54a8a620e708df7187eb2dda"), "x" : 5, "j" : 3 }
{ "_id" : ObjectId("54a8a620e708df7187eb2ddb"), "x" : 5, "j" : 4 }
{ "_id" : ObjectId("54a8a620e708df7187eb2ddc"), "x" : 5, "j" : 5 }
{ "_id" : ObjectId("54a8a620e708df7187eb2ddd"), "x" : 5, "j" : 6 }
{ "_id" : ObjectId("54a8a620e708df7187eb2dde"), "x" : 5, "j" : 7 }
{ "_id" : ObjectId("54a8a620e708df7187eb2ddf"), "x" : 5, "j" : 8 }
Type "it" for more
说明:请注意这里循环次数是50,但是只显示到第20条,还有其他数据没有显示出来,如果想继续查询下面的数据只需要使用it命令,就会继续显示下面的数据:
> it
{ "_id" : ObjectId("54a8a620e708df7187eb2de0"), "x" : 5, "j" : 9 }
{ "_id" : ObjectId("54a8a620e708df7187eb2de1"), "x" : 5, "j" : 10 }
{ "_id" : ObjectId("54a8a620e708df7187eb2de2"), "x" : 5, "j" : 11 }
{ "_id" : ObjectId("54a8a620e708df7187eb2de3"), "x" : 5, "j" : 12 }
{ "_id" : ObjectId("54a8a620e708df7187eb2de4"), "x" : 5, "j" : 13 }
{ "_id" : ObjectId("54a8a620e708df7187eb2de5"), "x" : 5, "j" : 14 }
{ "_id" : ObjectId("54a8a620e708df7187eb2de6"), "x" : 5, "j" : 15 }
{ "_id" : ObjectId("54a8a620e708df7187eb2de7"), "x" : 5, "j" : 16 }
{ "_id" : ObjectId("54a8a620e708df7187eb2de8"), "x" : 5, "j" : 17 }
{ "_id" : ObjectId("54a8a620e708df7187eb2de9"), "x" : 5, "j" : 18 }
{ "_id" : ObjectId("54a8a620e708df7187eb2dea"), "x" : 5, "j" : 19 }
{ "_id" : ObjectId("54a8a620e708df7187eb2deb"), "x" : 5, "j" : 20 }
{ "_id" : ObjectId("54a8a621e708df7187eb2dec"), "x" : 5, "j" : 21 }
{ "_id" : ObjectId("54a8a621e708df7187eb2ded"), "x" : 5, "j" : 22 }
{ "_id" : ObjectId("54a8a621e708df7187eb2dee"), "x" : 5, "j" : 23 }
{ "_id" : ObjectId("54a8a621e708df7187eb2def"), "x" : 5, "j" : 24 }
{ "_id" : ObjectId("54a8a621e708df7187eb2df0"), "x" : 5, "j" : 25 }
{ "_id" : ObjectId("54a8a621e708df7187eb2df1"), "x" : 5, "j" : 26 }
{ "_id" : ObjectId("54a8a621e708df7187eb2df2"), "x" : 5, "j" : 27 }
{ "_id" : ObjectId("54a8a621e708df7187eb2df3"), "x" : 5, "j" : 28 }
Type "it" for more
从技术上讲find()返回一个游标对象,但在上面的例子里,并没有拿到一个游标的变量,所以shell自动遍历游标,返回一个初始化的set,并允许我们继续用it迭代输出,当然我们也可以直接用游标输出,不过这个事游标部分的内容了。

1.5、_id key
MongoDB支持的数据类型中,_id是其自身产物,下面对其做些简单的介绍。
存储在MongoDB集合中的每个文档(document)都有一个默认的主键_id,这个主键名称是固定的,它可以使MongoDB支持的任何数据类型,默认是ObjectId,在关系数据库schema设计中,主键大多是数值型的,比如常用的int和long,并且更通畅的是主键的取值由数据库自增获得,这种主键数值的有序性有时也标明了某种逻辑,反观MongoDB,它设计之初就定位于分布式存储系统,所以它原生的不支持自增主键。
_id key举例说明:
当我们在往一个集合中写入一条文档时,系统会自动生成一个名为_id的key,如:
> db.xuz.find();
{ "_id" : ObjectId("54a8a4ff2db3e1b27d0e5203"), "name" : "mongo" }
{ "_id" : ObjectId("54a8a5042db3e1b27d0e5204"), "x" : 4 }
这里多出了一个类型为ObjectId的key,在插入的时候并没有指定,这有点类似Oracle的rowid的信息,属于自动生成的。
在MongoDB中,每一个集合都必须有一个叫做_id的字段,字段类型默认是ObjectId,换句话说,字段类型可以不是ObjectId,比如:
{ "_id" : ObjectId("54a8a621e708df7187eb2e08"), "x" : 5, "j" : 49 }
{ "_id" : ObjectId("54a8a621e708df7187eb2e09"), "x" : 5, "j" : 50 }
{ "_id" : 3, "name" : "zhangsan" }
虽然_id的类型可以自由指定,但是在同一个集合中必须唯一,如果插入重复的值的话,系统将会抛出异常,具体如下:
> db.xuz.insert({_id:3,"name":zhaoliu});
2015-01-04T10:41:26.289+0800 ReferenceError: zhaoliu is not defined
> db.xuz.insert({_id:3,"name":"zhaoliu"});
WriteResult({
        "nInserted" : 0,
        "writeError" : {
                "code" : 11000,
                "errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.xuz.$_id_  dup key: { : 3.0 }"
        }
})
说明:因为前面已经插入一条_id=3的记录,所以再插入相同的文档就不允许了。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。