MongoDB

一、MongoDB 简介

1. 百科

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

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

2. 与MySQL相比:

  • 数据模型,MongoDB是面向文档的数据库,MySQL是关系型数据库。
  • 查询语言,MongoDB不支持join,MySQL支持join。
  • 扩展性和性能,MongoDB使用可水平扩展的架构,MySQL使用垂直扩展的架构。
  • 可靠性,MongoDB目前只支持单文档事务,MySQL支持复杂事务操作。

3. 与Redis相比:

  • 数据存储方式:MongoDB使用文档存储方式,Redis使用键值对存储方式。
  • 数据类型:MongoDB可以存储各种类型的数据,包括文本、数字、日期、数组、嵌套文档等等,Redis主要用于存储简单的数据类型,如字符串、哈希表、列表、集合等等。
  • 存储方式:MongoDB使用磁盘存储数据,Redis则是将数据存储在内存中。因此,MongoDB可以存储更大量级的数据,而Redis则更适合处理较小、经常被访问的数据。
  • 数据访问:MongoDB提供强大的查询检索功能,而Redis仅支持基本的查询操作。
  • 扩展性:MongoDB可以水平扩展,支持分布式架构,而Redis主要是通过主从复制的方式实现高可用性和可扩展性。

4. 适合的场景:

  • 数据量大。
  • 读写操作频繁。
  • 数据价值较低,对事务要求不高。

二、MongoDB 创建/删除数据库

db.cloneDatabase("127.0.0.1");  // 从指定主机上克隆数据库

use database;

db.database.insertOne({"name":"B"});

db.dropDatabase();

三、MongoDB 创建/删除集合

db.createCollection("database");

db.database.drop();

四、插入/删除文档

db.collections.insert(obj)

db.collections.insertOne( obj, < optional params > ):返回插入主键

db.collections.insertMany( [objects], < optional params > ):批量插入,返回插入的主键

db.users.insertMany([
  {
    "name": "Johs",
    "age": 10,
    "email": "johs@example.com"
  },
  {
    "name": "John",
    "age": 30,
    "email": "john@example.com"
  },
  {
    "name": "Jane",
    "age": 25,
    "email": "jane@example.com"
  },
  {
    "name": "Bob",
    "age": 40,
    "email": "bob@example.com"
  }
])
db.users.insertMany

在创建集合期间,MongoDB 在 _id 字段上创建唯一索引,该索引可防止客户端插入两个具有相同的文档

db.collections.save(obj):主键不存在插入,存在则替换

db.collections.drop():删除集合

db.collections.remove({"字段":"值"}):删除满足条件的所有数据

db.collections.remove({"字段":"值"},true):删除满足条件的第一条数据


五、查询文档

db.collections.find(<条件>):查找所有文档,相当于 select * from user
条件字段如果是字符串,表示包含;如果是数组,表示精确匹配;$all:匹配多个元素;$size:元素个数;$slice:截取;$elemMatch:数组中是否有一个元素同时满足所有条件;$type:字段类型;$exists:字段是否存在;null:字段值是否为null或没有该字段

db.collection.findOne()

  • 比较查询:$lt 、$lte 、$gt 、$gte 、$ne

    db.users.find({"name" : {"$ne" : "John"}});
    
    db.users.find({"age" : {"$gte":20,"$lte": 30}});
    
  • 范围查询:$in、$nin

    db.users.find({"age" : {"$in" : [10, 30]}});// in不是between,是 = and =
    
  • $where:通过js函数自定义查询条件,此时不走索引

    db.users.find({"$where" : "function() { return this.age == 10; }"});
    
  • 正则表达式和数组

    db.users.find({"name" : {"$regex" : "Ja" }});
    
    db.users.find({"name" : {"$regex" : /Ja/ }});
    
    db.users.find({"name" : /Ja/ });
    
  • 条件查询:$and、$or

    db.users.find({"$or":[{"name":"Bob"},{"age":30}]});
    
  • 特殊函数:distinct、count、limit、skip、sort(正数升序)

    db.users.distinct();
    
    db.users.countDocuments();
    
    db.users.find().sort({"age":-1}).skip(1).limit(3);
    

聚合框架aggregate

  • $match筛选:相当于sql中的where

  • $project投射:查询指定字段、对字段起别名、使用算术表达式 $add、$subtract、$multiply、$divide、$mod 处理字段、$substrCP截取、$concat拼接、$toUpper/Lower转大小写、日期表达式、$cmp比较非字符串类型、$strcasecmp比较字符串、$and/or/not、$cond 三位运算符、ifNull(bool, default_value)

  • $group 分组、$unwind拆分、$sort、$limit、$skip

    示例:
    db.user.aggregate(
      {"$match": {"age": {"$gte" : 10} }},
      {"$group": {"_id": "$class", "count": {"$sum": 1}}},
      {"$sort": {"count": -1}},
      {"$skip": 1},
      {"$limit": 1}
    )
    上述聚合函数相当于:
    SELECT class, COUNT(*) AS count FROM user WHERE age >= 10 GROUP BY classORDER BY count DESC LIMIT 1 OFFSET 1;
    

六、MongoDB 更新文档

db.collection.update(<query>,<update>,
 {
  upsert: <boolean>,
  multi: <boolean>,
  writeConcern: <document>
 }
)

  • query : update的查询条件,类似sql update查询内where后面的。
  • update : update的对象和一些更新的操作符(如,inc...)等,也可以理解为sql update查询内set后面的
  • upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
  • multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
  • writeConcern :可选,抛出异常的级别。
  • 默认整体替换掉满足条件的文档而不是单独的修改指定字段的值

db.collection.update(query, update, insertOrUpdate)
若insertOrUpdate为true,则更新策略变为不存在则添加,存在则更新

db.collection.update(query, update, insertOrUpdate, multiUpdate) 批量更新

  • $set:字段存在则修改,不存在则添加。对应update中整个文档进行替换

  • $unset:删除字段。

  • $inc:字段递增/减

  • $push:字段尾部添加元素,若字段不存在则创建数组

  • $push + $each:添加多个元素

      db.user.update({"_id": 1}, {"$push": {"hobby": {"$each": ["money", "xiaojiejie"]}}})
    
  • $addToSet:向数组尾部添加不存在的元素,如果存在则不添加

  • $pop:弹出数组的头部元素或尾部元素: -1:头部,1:尾部。

  • $pull:删除数组中的指定的值。

db.collection.findAndModify({ “query”: xxx, “update”: xxx,upsert):查找满足添加的值并返回,并且修改满足条件的第一条文档


七、MongoDB 索引

db.collection.createIndex(keys, options); //创建索引
如果查询时发现没有使用到索引,可以使用hint函数强制使用索引查询

1. 索引类型

  • 唯一索引 unique;
  • 稀疏索引 sparse:包含索引必须唯一,不包含不用校验,对应唯一索引校验null
  • 复合索引
  • TTL 索引: 设置文档的缓存时间,时间到了会自动删除掉
  • 全文索引 text:便于大文本查询(如概要、文章等长文本)
  • 二维平面索引:便于2d平面查询;
  • 地理空间索引:便于地理查询

2. 索引选项

  • 复合索引 name:"", 自定义索引的名称,不配置系统会有默认的索引名。
  • 复合索引 background: true, 默认是前台模式, 创建索引是一件即费事又耗费资源的事情,创建索引是在前台模式或者后台模式下创建,在前台模式下创建非常快,但是当有读写请求时会堵塞,在后台模式下当有读写请求时并不堵塞,但是创建索引就会暂时暂停,后台模式要比前台模式慢的多。
  • 复合索引 unique/sparse: true,索引
  • 复合索引 dropDups: true,是否强制删除其他重复的文档,默认不删除,当索引键值重复时创建失败。

3. 对于索引的使用效率

  • 复合索引索引键基数越大,效率越高。一些特殊的操作符不能使用索引,一般取反的操作符索引利用率都比较低。
  • 复合索引如果能使用操作符尽量不要使用作符,因为or是执行两次查询操作,然后将结果合并起来,类似于union all,能使用in(单次查询)就不要使用or操作符。

八、MongoDB ObjectId

MongoDB中存储的文档必须有一个"_id"键。这个键的值可以是任何类型的,默认是个ObjectId对象。在一个集合里面,每个文档都有唯一的"_id"值,来确保集合里面每个文档都能被唯一标识。

MongoDB采用ObjectId,而不是其他比较常规的做法(比如自动增加的主键)的主要原因,因为在多个 服务器上同步自动增加主键值既费力还费时。

ObjectId 是一个12字节 BSON 类型数据,有以下格式:

  • 前4个字节表示时间戳
  • 接下来的3个字节是机器标识码
  • 紧接的两个字节由进程id组成(PID)
  • 最后三个字节是随机数。
ObjectId();

ObjectId("64d34d4fe31e1a71dd3e5355").getTimestamp(); // getTimestamp 函数可以获取文档的创建时间

九、MongoDB 复制

MongoDB复制是将数据同步在多个服务器的过程。复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。复制还允许您从硬件故障和服务中断中恢复数据。

MongoDB复制结构图

mongodb的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。

主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。

1. 添加副本集

replSet 选项

mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME"
实例:
mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0
以上实例会启动一个名为rs0的MongoDB实例,其端口号为27017。

启动后打开命令提示框并连接上mongoDB服务。
在Mongo客户端使用命令rs.initiate()来启动一个新的副本集,使用rs.conf()来查看副本集的配置,使用 rs.status() 查看副本集状态。

rs.add 命令

rs.add(HOST_NAME:PORT)
实例:
假设你已经启动了一个名为mongod1.net,端口号为27017的Mongo服务。 在客户端命令窗口使用rs.add() 命令将其添加到副本集中,命令如下所示:
rs.add("mongod1.net:27017")

MongoDB中你只能通过主节点将Mongo服务添加到副本集中,判断当前运行的Mongo服务是否为主节点可以使用命令db.isMaster() 。

MongoDB的副本集与我们常见的主从有所不同,主从在主机宕机后所有服务将停止,而副本集在主机宕机后,副本会接管主节点成为主节点,不会出现宕机的情况。


十、MongoDB 分片

在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求。

当MongoDB存储海量的数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量。这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。

MongoDB分片集群结构分布

上图中主要有如下所述三个主要组件:

  • Shard:
    用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个replica set承担,防止主机单点故障
  • Config Server:
    mongod实例,存储了整个 ClusterMetadata,其中包括 chunk信息。
  • Query Routers:
    前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。

1. 为什么使用分片

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

推荐阅读更多精彩内容