MongoDB闪亮登场

自我介绍

MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。

MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

MongoDB最大的特点就是无Schema限制,灵活度很高。数据格式是BSON,BSON是一种类似JSON的二进制形式的存储格式,简称Binary JSON 它和JSON一样,支持内嵌的文档对象和数组对象。

跟关系型数据库概念对比

Mysql MongoDB
Database(数据库) Database(数据库)
Table(表) Collection(集合)
Row(行) Document(文档)
Column(列) Field(字段)

数据格式

MongoDB 将数据存储为一个文档,BSON格式。由key 和 value组成。


"_id" : ObjectId("5e141148473cce6a9ef349c7"),
    "title" : "批量更新", 
    "url" : "http://cxytiandi.com/blog/detail/8", 
    "author" : "yinjihuan", 
    "tags" : [
        "java", 
        "mongodb", 
        "spring"
    ], 
    "visit_count" : NumberLong(10), 
    "add_time" : ISODate("2019-02-11T07:10:32.936+0000")
}

使用场景

  • 大数据量存储场景

MongoDB自带副本集和分片,天生就适用于大数量场景,无需开发人员通过中间件去分库分表,非常方便。

  • 操作日志存储

很多时候,我们需要存储一些操作日志,可能只需要存储比如最近一个月的,一般的做法是定期去清理,在MongoDB中有固定集合的概念,我们在创建集合的时候可以指定大小,当数据量超过大小的时候会自动移除掉老数据。

  • 爬虫数据存储

爬下来的数据有网页,也有Json格式的数据,一般都会按照表的格式去存储,如果我们用了MongoDB就可以将抓下来的Json数据直接存入集合中,无格式限制。

  • 社交数据存储

在社交场景中使用 MongoDB 存储存储用户地址位置信息,通过地理位置索引实现附近的人,附近的地点等。

  • 电商商品存储

不同的商品有不同的属性,常见的做法是抽出公共的属性表,然后和SPU进行关联,如果用MongoDB的话那么SPU中直接就可以内嵌属性。

自我陶醉

MongoDB的功能点很多,但是大部分场景下我们只用了最简单的CRUD操作。下面隆重的介绍下MongoDB的功能点,就像你去相亲一样,不好好介绍自己的优点又怎能让你对面的菇凉心动呢?

CRUD

CRUD也就是增删改查,这是数据库最基本的功能,查询还支持全文检索,GEO地理位置查询等。

  • db.collection.insertOne()

单个文档插入到集合中

  • db.collection.insertMany()

多个文档插入到集合中

  • db.collection.insert()

单个或者多个文件插入到集合中

  • db.collection.find( )

查询数据

  • db.inventory.updateOne()

更新单条

  • db.inventory.updateMany()

更新多条

  • db.inventory.deleteOne( )

删除单条文档

  • db.inventory.deleteMany()

删除多条文档

Aggregation

聚合操作用于数据统计方面,比如Mysql中会有count,sum,group by等功能,在MongoDB中相对应的就是Aggregation聚合操作。

聚合下面有两种方式来实现我们需要对数据进行统计的需求,一个是aggregate,一个是MapReduce。

下图展示了aggregate的执行原理:

聚合内置了很多函数,使用好了这些函数我们就可以统计出我们想要的数据。

$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。

$match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。

$limit:用来限制MongoDB聚合管道返回的文档数。

$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。

$group:将集合中的文档分组,可用于统计结果。

$sort:将输入文档排序后输出。

$geoNear:输出接近某一地理位置的有序文档。

$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。

下图展示了MapReduce的执行原理:

总共4条数据,query指定了查询条件,只处理status=A的数据。

map阶段对数据进行分组聚合,也就是形成了第三部分的效果,根据cust_id去重统计。

reduce中的key也就是cust_id, values也就是汇总的amount集合。然后进行sum操作,最终的结果通过out输出到一个集合中。

Transactions

MongoDB最开始是不支持事务的,在MongoDB中,对单个文档的操作是原子性操作。所以再设计的时候可以使用嵌入的文档和数组来描述数据之间的关系,这样就不用跨多个文档和集合进行操作,也就通过了单文档原子性消除了许多实际用例对多文档事务的需要。

任何事物都是有限制的,某些场景还是不能完全通过内嵌的方式来描述数据的关系,还是会存在多个集合,对于使用MongoDB的用户来说,如果能支持事务就很方便了。

不负众望,MongoDB 4.0 版本的发布,为我们带来了原生的事务操作。

Indexes

索引不用我多说了,作用大家都知道。单索引,组合索引,全文索引,Hash索引等。

db.collection.createIndex({user_id: 1, add_time: 1}, {background: true})

创建索引特别要注意的是将background设置为true,在建索引的过程会阻塞其它数据库操作,background可指定以后台方式创建索引,默认为false。这可是血的教训呀,切记切记。

Security

MongoDB中的安全需要重视,目前启动不知道有没有强制的限制,以前启动的时候可以不指定认证的方式,也就是不需要密码即可访问,然后很多人都直接用的默认端口,暴露在公网上,给不法分子有机可乘,出现了数据被删,需要用比特币来找回数据的案例比比皆是。

还是要开启安全认证,内置了很多角色,不同的角色可操作的内容不一样,控制的比较细。

Replication

副本集是一组相同数据集的MongoDB实例,同时在多个节点存储数据,提高了可用性。主节点负责写入,从节点负责读取,提高整体性能。

副本集由下面的组件构成:

Primary:主节点接收所有的写操作。

Secondaries:从节点会从主节点进行数据的复制,维护跟主节点相同的数据。用于查询操作。

Arbiter:仲裁节点本身不存储数据,只参与选举。

Sharding

分片是MongoDB绝对的亮点,将数据水平拆分到多个节点。MongoDB的分片是全自动的,我们只需要配置好分片的规则,它就能自动维护数据并存储到不同节点。MongoDB使用分片来支持大数据量的存储和高吞吐量的操作。

下图是Mongodb的分片集群架构图:

MongoDB分片集群由以下组件够成:

Shard:每个shard的数据都是独立完整的一份。并且可以作为副本集部署。

mongos:mongos是查询路由器,在客户端和服务端中间的一层,请求会直接到mongos,由mongos路由到具体的Shard。

Config Servers:存储集群所有节点、分片数据路由信息。

GridFS

GridFS是MongoDB的一个子模块,主要用于在MongoDB中存储文件,相当于MongoDB内置的一个分布式文件系统。

本质上还是讲文件的数据分块存储在集合中,默认的文件集合分为fs.files和fs.chunks。

fs.files是存储文件的基本信息,比如文件名,大小,上传时间,md5等。fs.chunks是存储文件真正数据的地方,一个文件会被分割成多个chunk块进行存储,一般为256k/个。

如果你的项目中用到了MongoDB,那么你可以使用GridFS来构建一个文件系统,这样就不用去购买第三方的存储服务了。

GridFS的好处是你不用单独去搭建一个文件系统,直接使用Mongodb自带的即可,备份,分片都依赖MongoDB,维护起来也方便。

知识点总结

下图是我自己总结的一些知识点,作为一个后端开发来说,能掌握下面的内容就已经不错了,毕竟我们又不是要去抢DBA的饭碗,如果大家业余时间要学习的话可以按照下面的点进行学习,几年前我录制了一套视频,在我的网站上,大部分内容都覆盖到了。

工作必用

MongoDB跟Mysql的语法对比



Spring Boot中集成MongoDB

加入MongoDB的依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

配置MongoDB的信息:

spring.data.mongodb.database=test
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
// 用户名,密码省略.......

直接注入MongoTemplate就可以操作MongoDB:

@Autowired
private MongoTemplate mongoTemplate;

使用示列

创建一个实体类,对应MongoDB的集合

@Data
@Document(collection = "article_info")
public class Article {
@Id
@GeneratedValue
private Long id;
@Field("title")
private String title;
@Field("url")
private String url;
@Field("author")
private String author;
@Field("tags")
private List<String> tags;
@Field("visit_count")
private Long visitCount;
@Field("add_time")
private Date addTime;
}

最终存储到数据中的格式如下:


"_id" : ObjectId("5e141148473cce6a9ef349c7"),
    "title" : "批量更新", 
    "url" : "http://cxytiandi.com/blog/detail/8", 
    "author" : "yinjihuan", 
    "tags" : [
        "java", 
        "mongodb", 
        "spring"
    ], 
    "visit_count" : NumberLong(10), 
    "add_time" : ISODate("2019-02-11T07:10:32.936+0000")
}

插入数据

Article article = new Article();
article.setTitle("MongoTemplate 的基本使用 ");
article.setAuthor("yinjihuan");
article.setUrl("http://cxytiandi.com/blog/detail/1");
article.setTags(Arrays.asList("java", "mongodb", "spring"));
article.setVisitCount(0L);
article.setAddTime(new Date());
mongoTemplate.save(article);

数据库语法

db.article_info.save({
"title": "批量更新",
"url": "http://cxytiandi.com/blog/detail/8",
"author": "yinjihuan",
"tags": [
"java",
"mongodb",
"spring"
],
"visit_count": NumberLong(10),
"add_time": ISODate("2019-02-11T07:10:32.936+0000")
})

更新数据

Query query = Query.query(Criteria.where("author").is("yinjihuan")); 
Update update = Update.update("title", "MongoTemplate")
.set("visitCount", 10); 
mongoTemplate.updateMulti(query, update, Article.class);

数据库语法

db.article_info.updateMany(
{"author":"yinjihuan"}, 
{"$set":
  {
    "title":"MongoTemplate", 
    "visit_count": NumberLong(10)
  }
}
)

删除数据

Query query = Query.query(Criteria.where("author").is("yinjihuan")); 
mongoTemplate.remove(query, Article.class);

数据库语法

db.article_info.remove({"author":"yinjihuan"})

查询数据

Query query = Query.query(Criteria.where("author").is("yinjihuan")); 
List<Article> articles = mongoTemplate.find(query, Article.class);

数据库语法

db.article_info.find({"author":"yinjihuan"})

存储文件

File file = new File("/Users/yinjihuan/Downloads/logo.png");
InputStream content = new FileInputStream(file);
// 存储文件的额外信息,比如用户ID,后面要查询某个用户的所有文件时就可以直接查询
DBObject metadata = new BasicDBObject("userId", "1001");
ObjectId fileId = gridFsTemplate.store(content, file.getName(), "image/png", metadata);

源码参考

https://github.com/yinjihuan/spring-cloud/tree/master/Spring-Cloud-Book-Code-2/ch-17/mongodb

客户端推荐

下载地址:

https://studio3t.com/download/

spring-boot-starter-mongodb-pool

最后推荐一个我自己写的小框架:Spring Boot中增强Mongodb的配置,多数据源,连接池

https://github.com/yinjihuan/spring-boot-starter-mongodb-pool

恕我直言,牛逼哄哄的MongoDB你可能只会30%的更多相关文章

  1. 为什么我会认为SAP是世界上最好用最牛逼的ERP系统,没有之一?

    为什么我认为SAP是世界上最好用最牛逼的ERP系统,没有之一?玩过QAD.Tiptop.用友等产品,深深觉得SAP是贵的有道理! 一套好的ERP系统,不仅能够最大程度承接适配企业的管理和业务流程,在技 ...

  2. 我喜欢ASP.NET的MVC因为它牛逼的9大理由(转载)

    我很早就关注ASP.NET的mvc的,因为最开始是学了Java的MVC,由于工作的原因一直在做.Net开发,最近的几个新项目我采用了MVC做了,我个一直都非常喜欢.Net的MVC.我们为什么使用MVC ...

  3. 最牛逼android上的图表库MpChart(三) 条形图

    最牛逼android上的图表库MpChart三 条形图 BarChart条形图介绍 BarChart条形图实例 BarChart效果 最牛逼android上的图表库MpChart(三) 条形图 最近工 ...

  4. 最牛逼android上的图表库MpChart(二) 折线图

    最牛逼android上的图表库MpChart二 折线图 MpChart折线图介绍 MpChart折线图实例 MpChart效果 最牛逼android上的图表库MpChart(二) 折线图 最近工作中, ...

  5. 最牛逼android上的图表库MpChart(一) 介绍篇

    最牛逼android上的图表库MpChart一 介绍篇 MpChart优点 MpChart是什么 MpChart支持哪些图表 MpChart效果如何 最牛逼android上的图表库MpChart(一) ...

  6. .Net免费公开课视频+资料+源码+经典牛逼 汇总篇【持续更新】

    博主推荐一:WP8.1最经典培训教程 博主点评:经典Windows Phone8.1 Runtime API培训最经典教程,此教程由传智播客蒋坤老师录制的一整套WP8.1入门级视频教程,讲授内容非常广 ...

  7. 科学家有了钱以后,真是挺吓人的——D.E.Shaw的牛逼人生

    科学家有了钱以后,真是挺吓人的——D.E.Shaw的牛逼人生 黑科技,还是要提D.E.Shaw Research这个奇异的存在. 要讲这个黑科技,我们可能要扯远一点,先讲讲D.E. Shaw这个人是怎 ...

  8. cssViewer牛逼的chrome插件

    很牛逼,功能很强大.

  9. NBU是最牛逼的备份软件

    NBU是最牛逼的备份软件 TSM是IBM的备份   好好看看几个厂商 VERITAS 公司下的NBU入门级备份有BEHP的备份软件有DPIBM的是TSMCommvault也非常牛逼这都是做到了小机AI ...

随机推荐

  1. Python--day47--mysql执行计划

    1,什么是mysql执行计划? 让mysql预估执行操作:在要执行的语句前面加explain,就不会真的执行sql语句,只是给出了要执行的数据的情况,如大约有多少条,查询类型.

  2. Codeforces Round #177 (Div. 1 + Div. 2)

    A. Polo the Penguin and Segments 模拟. B. Polo the Penguin and Matrix 每个数字模d余数必须一样. 枚举结果,可计算操作次数,取最小. ...

  3. [转]Spring 注解大全与详解

    Spring使用的注解大全和解释 注解 解释 @Controller 组合注解(组合了@Component注解),应用在MVC层(控制层),DispatcherServlet会自动扫描注解了此注解的类 ...

  4. Redis 命令行工具能这样用你知道了吗?

    我们天天都在使用 Redis 内置的命令行工具 redis-cli,久而久之以为它就是一个简单的交互式 Redis 数据结构手工操作程序,但是它背后强大的功能绝大多数同学可能闻所未闻.本节我们一起来挖 ...

  5. C# 标准性能测试高级用法

    本文告诉大家如何在项目使用性能测试测试自己写的方法 在 C# 标准性能测试 已经告诉大家如何使用 BenchmarkDotNet 测试性能,本文会告诉大家高级的用法. 建议是创建一个控制台项目用来做性 ...

  6. ZOJ3537 Cake

    ZOJ3537 Cake 传送门:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3537 题意: 给你几何形状的蛋糕,你需要 ...

  7. 基于bootstrap3.3.4的简单框架搭建(左侧导航收起滚动)

    前提:博主本人做.net方向的2年多了 去年的后半年公司要做基于bootstrap框架的后台,由于没有经验,然后跟公司美工一块从0开始折腾,对这个框架不是太熟悉,然后就开始各种自己写js写css的往里 ...

  8. python简单小程序

    #足球队寻找10 到12岁的小女孩(包含10岁和12岁),编写程序询问用户性别和年龄,然后显示一条消息指出这个人是否可以加入球队,询问10次,输出满足条件的总人数#询问10次,输出满足要求的总人数 o ...

  9. 第二阶段:2.商业需求分析及BRD:3.产品需求分析

    产品需求收集之后就可以进行产品需求分析了. 比如微信功能的逐步完善,偏向于做加法,但有时候也会做减法. Y轴是重要跟不重要 X轴是紧急跟不紧急 然后通过各个需求的分数来确定坐标位置.同时可以根据阶段调 ...

  10. Web的大趋势:Java+大前端

    前后端分离,是目前Web开发的主流模式.而Java无疑是后端开发的王者,PHP和.NET目前仍处于水深火热之中,更像是在夹缝中求生存.而大前端,强势崛起!Java+大前端这一强强组合,面对其他Web领 ...