浅谈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 的优点和缺点

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容