浅谈MongoDB数据库


浅谈MongoDB数据库


简介

最近项目中需要分析Http报文,并且需要用数据库保存,刚刚开始打算用Mysql,后来咨询了老司机,老司机建议使用MongoDB来实现,所以特写一篇文章来总结下。

MongoDB 介绍

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

上面是百度百科的介绍,这里是MongoDB的官网

简单来说MongoDB是一种数据库,不过是非关系型数据库,它的一些概念和数据库不太一样。

MongoDB中一些概念和普通数据库不太一样,普通数据库有database、table、row、field的概念,MongoDB依次叫database、collection、document、field,这个在后面的代码示例会有体现。

数据库安装

因为用的是Mac,简单介绍下MongoDB在Mac上面的安装,Windows用户可以参考官网。

Mac上安装,直接使用Homebrew就可以了,如果不清楚Homebrew是什么,可以参考这里

brew 安装MongoDB

brew install mongodb

结果如下

$ brew install mongodb
Updating Homebrew...
==> Downloading https://homebrew.bintray.com/bottles/mongodb-3.4.9.sierra.bottle.tar.gz
######################################################################## 100.0%
==> Pouring mongodb-3.4.9.sierra.bottle.tar.gz
==> Caveats
To have launchd start mongodb now and restart at login:
  brew services start mongodb
Or, if you don't want/need a background service you can just run:
  mongod --config /usr/local/etc/mongod.conf
==> Summary
🍺  /usr/local/Cellar/mongodb/3.4.9: 19 files, 284.9MB

上面给的信息说明很清楚,如果当做一个服务器来用,直接用brew services start mongodb就行了,如果只是作为一个程序,那么用mongod --config /usr/local/etc/mongod.conf启动,/usr/local/etc/mongod.conf是默认配置文件。

我们可以看下配置文件内容,分别是日志路径、存储路径。最后一个是IP访问设置,默认只能本地访问,如果其他机器需要访问这个数据库,需要在配置文件中添加对应的IP。假如想省事,可以设置为0.0.0.0,那么任意机器都是可以访问的。

$ cat /usr/local/etc/mongod.conf
systemLog:
  destination: file
  path: /usr/local/var/log/mongodb/mongo.log
  logAppend: true
storage:
  dbPath: /usr/local/var/mongodb
net:
  bindIp: 127.0.0.1

MongoDB使用

我这里就简单开启一个MongoDB服务,直接调用brew services start mongodb就行了,这样MongoDB就启动了。

使用mongo命令即可进入MongoDB控制台。

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

下面简单演示数据库的增删改查,具体用法请参考官方CRUD文档

创建一个abc123的database

use abc123

创建一个user的collection,并插入两条数据。

> db.user.insert({name:'aaa'})
WriteResult({ "nInserted" : 1 })

> db.user.insert({name:'bbb',age:22})
WriteResult({ "nInserted" : 1 })

查看user中的数据

> db.user.find()
{ "_id" : ObjectId("59bf7bde5d6768f6ee06de2b"), "name" : "aaa" }
{ "_id" : ObjectId("59bf7d045d6768f6ee06de2c"), "name" : "bbb", "age" : 22 }

根据条件查询

> db.user.find({name:'bbb'})
{ "_id" : ObjectId("59bf7d045d6768f6ee06de2c"), "name" : "bbb", "age" : 22 }

修改数据

> db.user.updateOne({name:'aaa'},{$set:{age:11}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

> db.user.find();
{ "_id" : ObjectId("59bf7bde5d6768f6ee06de2b"), "name" : "aaa", "age" : 11 }
{ "_id" : ObjectId("59bf7d045d6768f6ee06de2c"), "name" : "bbb", "age" : 22 }

删除数据

> db.user.deleteMany({name:'aaa'})
{ "acknowledged" : true, "deletedCount" : 1 }

> db.user.find()
{ "_id" : ObjectId("59bf7d045d6768f6ee06de2c"), "name" : "bbb", "age" : 22 }

刚刚开始说过,Mongo的数据结构是类似于json的数据结构,数据里面的”_id”就是主键,是系统自己生成的。

当然也可以自己指定,在插入数据的时候,指定”_id”字段即可。

> db.user.insert({"_id":"12345",name:"Hello"})
WriteResult({ "nInserted" : 1 })

> db.user.find()
{ "_id" : ObjectId("59bf7d045d6768f6ee06de2c"), "name" : "bbb", "age" : 22 }
{ "_id" : "12345", "name" : "Hello" }

> db.user.insert({"_id":"12345",name:"Hello"})
WriteResult({
	"nInserted" : 0,
	"writeError" : {
		"code" : 11000,
		"errmsg" : "E11000 duplicate key error collection: abc123.user index: _id_ dup key: { : \"12345\" }"
	}
})

上面示例表示,第一次插入数据的时候,是成功的,查询结果也是符合预期,当再次执行的时候,插入失败,说明主键冲突。

MongoDB可视化工具

上面使用的是命令行工具查看数据,可能对有些同学不是很优化,我在这里推荐一款可视化功工具Robo 3T

用Robo 3T查看数据就很方便了。

Java操作MongoDB

Java操作Mongo比较简单,直接调用MongoDB的驱动即可,其他部分基本上和上面的语法一样。

本次使用的版本是3.5.0,下面是依赖方式。

<dependencies>
    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongodb-driver</artifactId>
        <version>3.5.0</version>
    </dependency>
</dependencies>
dependencies {
  compile 'org.mongodb:mongodb-driver:3.5.0'
}

数据库连接

private MongoClient client;

@Before
public void before() {
    String url = "mongodb://127.0.0.1:27017/abc123";
    MongoClientURI uri = new MongoClientURI(url);
    client = new MongoClient(uri);
}

查询数据

@Test
public void testFind() {
    MongoDatabase database = client.getDatabase("abc123");
    MongoCollection<Document> collection = database.getCollection("user");

    for (Document document : collection.find()) {
        for (Map.Entry<String, Object> entry : document.entrySet()) {
            System.out.print(entry.getKey() + ":" + entry.getValue() + "\t");
        }
        System.out.println();
    }
}

根据先前的数据,查到的结果2条。

_id:59bf7d045d6768f6ee06de2c	name:bbb	age:22.0
_id:12345	name:Hello

添加数据

@Test
public void testInsert() {
    testFind();

    MongoDatabase database = client.getDatabase("abc123");
    MongoCollection<Document> collection = database.getCollection("user");
    Document document = new Document();
    document.put("name", "World");
    document.put("age", 33);
    collection.insertOne(document);

    testFind();
}

插入前总共为2条数据,插入后为3条数据。

_id:59bf7d045d6768f6ee06de2c	name:bbb	age:22.0
_id:12345	name:Hello

_id:59bf7d045d6768f6ee06de2c	name:bbb	age:22.0
_id:12345	name:Hello
_id:59bf8282fe37ad04a81fd012	name:World	age:33

修改数据

@Test
public void testUpdate() {
    System.out.println("before update");
    testFind();

    MongoDatabase database = client.getDatabase("abc123");
    MongoCollection<Document> collection = database.getCollection("user");
    collection.updateMany(
            Filters.eq("name", "World"),
            Updates.set("age", 44)
    );

    System.out.println();
    System.out.println();
    System.out.println("after update");
    testFind();
}

修改数据和其他的不一样,collection.updateMany有2个参数,第一个参数Filters.eq("name", "World")是查询条件,第二个参数Updates.set("age", 44)为赋值语句。

在修改前数据为_id:59bf8282fe37ad04a81fd012 name:World age:33,修改后就变成了_id:59bf8282fe37ad04a81fd012 name:World age:44

before update
_id:59bf7d045d6768f6ee06de2c	name:bbb	age:22.0
_id:12345	name:Hello
_id:59bf8282fe37ad04a81fd012	name:World	age:33


after update
_id:59bf7d045d6768f6ee06de2c	name:bbb	age:22.0
_id:12345	name:Hello
_id:59bf8282fe37ad04a81fd012	name:World	age:44

删除数据


@Test
public void testDelete() {
    System.out.println("before delete");
    testFind();

    MongoDatabase database = client.getDatabase("abc123");
    MongoCollection<Document> collection = database.getCollection("user");
    collection.deleteMany(
            Filters.eq("name", "World")
    );

    System.out.println();
    System.out.println();
    System.out.println("after delete");
    testFind();
}

删除前有三条数据,删除后只有2条数据。

before delete
_id:59bf7d045d6768f6ee06de2c	name:bbb	age:22.0
_id:12345	name:Hello
_id:59bf8282fe37ad04a81fd012	name:World	age:44


after delete
_id:59bf7d045d6768f6ee06de2c	name:bbb	age:22.0
_id:12345	name:Hello

总结

总的来说,MongoDB使用还是很简单的,相对于传统的关系型数据库,优缺点表现如下。

优点:

  • 面向文档存储(类JSON数据模式简单而强大)

  • 动态查询

  • 全索引支持,扩展到内部对象和内嵌数组

  • 查询记录分析

  • 快速,就地更新

  • 高效存储二进制大对象 (比如照片和视频)

  • 复制和故障切换支持

  • Auto- Sharding自动分片支持云级扩展性

  • MapReduce 支持复杂聚合

  • 商业支持,培训和咨询

缺点:

  • 不支持事务(进行开发时需要注意,哪些功能需要使用数据库提供的事务支持)

  • MongoDB占用空间过大 (不过这个确定对于目前快速下跌的硬盘价格来说,也不算什么缺点了)

  • MongoDB没有如MySQL那样成熟的维护工具,这对于开发和IT运营都是个值得注意的地方

  • 在32位系统上,不支持大于2.5G的数据(很多操作系统都已经抛弃了32位版本,所以这个也算不上什么缺点了,3.4版本已经放弃支持32 位 x86平台)

相关资料

MongoDB的官网

Homebrew

官方CRUD文档

Robo 3T

MongoDB 的优点和缺点


文章作者: 流水不腐小夏
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 流水不腐小夏 !
 上一篇
使用MyMockServer模拟数据 使用MyMockServer模拟数据
使用MyMockServer模拟数据 简介在开发的时候,前端、移动端、后端开发分离,开发流程是先定义好接口API,然后按照接口约定进行开发。所以经常需要根据接口Mock数据,有从代码层进行Mock,也有从网络层进行代理的。 本人使用方式是在
2017-10-13 流水不腐小夏
下一篇 
  目录