mongodb 分组聚合_MongoDB常用操作命令介绍

本文主要介绍了MongoDB的基础知识和常用操作,包括MongoDB的非关系型数据库特性、BSON格式和索引。重点讲解了MongoDB的CRUD操作、分片、聚合管道命令以及查询计划分析,提供了各种命令的示例和注意事项,帮助读者掌握MongoDB的实战技能。
摘要由CSDN通过智能技术生成

fb49b0adf1900db369867ce398a7da34.png

注:本文主要介绍在实际工作中常用到的一些MongoDB操作,基于3.2.5版本的MongoDB集群环境。[1]

MongoDB简介

先介绍下MongoDB,帮助还没接触过的同学更好理解后面的命令,下面是百度百科的资料:

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

其中主要是三个关键字:

  • “非关系数据库”:意味着每张表的字段不被强制固定,不需要像mysql等关系数据库一样提前建立表-字段的关系,你可以在表中插入任意字段组合的文档。
  • “类似json的bson格式”:MongoDB设计之初就是为WEB应用提供存储方案,所以天然支持javascript语法,包括下面要介绍的shell命令都可以按js语法来理解,而对于MongoDB中数据的格式在应用层基本上可以直接当做JSON来看待。
  • “索引”:作为能够快速查询海量数据的重要依赖,MongoDB支持多种索引,常用的包括_id索引(默认唯一索引,自动创建),复合索引,全文索引等。

MongoDB的结构如下:

6b2d7b15e8ebb09275fea97c923bc3ed.png

基础mongo shell命令

show dbs //展示服务器上的db列表,只有进行过相关数据操作的数据库才会被创建并显示
use testdb1 //切换至testdb1,进入shell默认在'test'数据库下
show collections //展示数据库下的集合列表
db.dropDatabase() //删除当前数据库
db.testcoll1.drop() //删除当前集合
testdb1=db.getSiblingDB('testdb1') //获取testdb1的引用,切换到其它库时就可以通过testdb1.xxx来跨库操作
coll=db.testcoll1 //获取集合应用,可用于简化后续集合操作
db.stats() //查看当前数据库状态
db.testcoll1.status() //查看集合状态:索引、分片等
db.testcoll1.getIndexes() //查看集合的索引列表
db.testcoll1.createIndex({a:1,b:-1},{name:'a_1_b_-1',unique:true,background:true}) //在集合’testcoll1’上创建a顺序b倒序的复合唯一索引,语法createIndex(keys,options),复合索引中keys不能使用hash索引,options中name表示索引名称,示例就是mongo索引名称的默认规则,uniqe指定是否唯一索引,默认非唯一,background指定在后台逐步创建索引,这样不会阻塞其它db操作,在已有大数据量的集合中应使用该选项

MongoDB分片

d92ba47dae3094b3f3178258572ed263.png

分片(sharding)是MongoDB的一种集群特性,用于满足海量数据的存储和访问需求,简单来说就是将数据按照预定的某种规则(片键)分布存储在集群中的多台机器(shard)上,通过查询路由(query router)和配置服务(config server)来为应用提供透明的操作方式,就像在操作单一数据库一样。

各个shard上的存储单元chunk是由某部分范围片键多个文档组成为了获得最佳的分片效果,必须选择一个合适的片键:既能够保证数据的均匀分布、分散写入,又能在大部分业务查询条件下缩小分片范围以保证查询效率。

片键在创建后无法再更改,片键必须是集合的索引,如果是空集合则自动创建,同时不允许无片键的文档插入集合,下面介绍分片的常用命令。

sh.enableSharding("testdb1") //在指定数据库上启用分片
sh.shardCollection(collection,key,{a:"hashed"}) //进行集合分片,片键为a字段的hash索引,可选的还有普通索引和范围索引
db.runCommand({shardCollection:"testdb1.testcoll1",key:{a:"hashed"},numInitialChunks:1024}) //通过在admin库执行该命令建立分片集合可以预创建指定数量的chunk块,用以在生产环境减少chunk块初始分裂频率
sh.status() //展示所有集合的分片信息,包括chunks情况,当集群较庞大时填入{"verbose":1}参数来显示所有信息
db.testcoll1.getShardDistribution() //展示集合的每个分片大小状态,可用于查看集合是否均匀分布

MongoDB CRUD操作命令

db.coll.insert({a:1,b:2}) //插入文档
db.coll.find({a:1,b:2},{a:1,b:1})  //select a,b from coll where a=1 and b=2,属性为非嵌套文档字段时可以省略引号,第二个参数指定要返回的字段,默认全部字段(_id字段除非指定不返回,否则默认都会返回)。返回结果是cursor对象,可以继续使用sort()、limit()、count()等方法进一步处理,下面介绍常用的查询函数符号
db.coll.find({$or:[{a:{$lt:10,$gte:1}},{b:{$exists:true}}]}) //where (a<10 and a>=1) or b<>'',类似的函数符号还有$eq,$ne,$in,$nin,$and,$not,$nor等等
db.coll.find({a:{$regex:/test.*/}}) //where a like 'test%',通过正则表达式实现模糊匹配
db.coll.find({$where:"this.c!=null && this.c.length>3"}) //通过js表达式查询,可以使用js中的原生函数,但注意$where需要遍历所有文档并转换为json去匹配js表达式,使用时一定要考虑性能问题
db.coll.update({a:1},{$set:{b:2},$inc:{c:1}},{multi:false,upsert:false}) //update coll set b=2,c=c+1 where a=1,可选参数upsert(无匹配文档时是否组合条件插入:{a:1,b:2,c:1})、multi(是否更新所有匹配文档)。其他更新函数有$unset,$setOnInsert,$currentDate,$min,$max。与update类似的还有findAndModify用于实现原子操作

接下来介绍数组的常用操作

db.coll.find({a:{$all:[1,2]},b:{$size:3}}) //$all用于查询包含指定元素数组的文档,$size匹配指定长度的数组
db.coll.find({a:{$elemMatch:{$lt:4,$gt:2}}},{a:{$elemMatch:{$eq:3}}}) //$elemMatch在查询条件中可针对数组的每个元素进行条件匹配,而在输出字段中用于返回数组中第一个匹配的元素。例:文档{a:[1,2,3,3,4]},结果{a:[3]}
db.coll.update({a:1},{$pull:{a:{$lt:2}}}) //$pull删除匹配的元素
db.coll.update({a:1},{$push:{a:2}}) //$push数组末尾插入元素
db.coll.update({a:1},{$addToSet:{a:{$each:[2,3,4]}}}) //$addToSet去重插入元素,$each与$push或$addToSet组合可追加或去重合并数组
db.coll.update({a:1},{$pop:{a:1}}) //$pop删除数组开头(-1)结尾(1)的元素
db.coll.update({"a.b":1},{$set:{"a.$.c":3}}) //"a.$"是数组字段的特殊用法,是数组第一个匹配元素的引用,可用于更新数组嵌套文档。例:文档{a:[{b:1,c:2},{b:1,c:4}]},结果{a:[{b:1,c:3},{b:1,c:4}]}

MongoDB聚合管道命令

聚合是MongoDB中用于数据处理和复杂查询的重要操作,诸如sql中的子查询、group by,count(*)都可以通过聚合来实现,基本语法:db.coll.aggregate(pipeline,options),其中pipeline指一条数据处理流水线,由多个聚合管道命令组成,类似linux shell命令的管道概念,如下图所示,下面介绍常用的聚合管道命令:

8cdf9757f9ef80c15bb55f2ae2a281d1.png
  • $match:用于按条件筛选文档,语法与普通的find查询条件相同
  • $project:用于指定要返回的字段或者添加新字段,例:{$project:{a:1,b:{$eq:["$a","test"]}}},上述指定返回字段"a"并添加字段"b"计算字段"a"的值是否等于"test"
  • $group:与sql中的group by类似,例:{$group:{_id:"$a",count:{$sum:"$b"},c:{$first:"$c"}}},上述指定以"a"字段分组,字段"count"计算每个分组下字段“b”数值总和,并在分组中返回第一个"c"字段的值。(在3.2版本中由于不支持$count管道命令,因此只能使用{$group:{_id:null,count:{sum:1}}}的格式来计算管道某一阶段的文档总数)
  • $unwind:展开数组字段,当需要聚合一个数组字段的值时,可以先使用$unwind拆分数组然后使用$addToSet合并
  • $sort:文档排序,与cursor.sort()类似
  • $skip:跳过指定个数的文档
  • $limit:限制文档返回数量
  • $out:将聚合的结果写入指定的集合中,当我们需要通过导出聚合后的数据时可以使用该操作先转存至其他集合,再使用mongoexport普通导出

在实际组合使用上述管道操作时,需注意各操作的顺序以优化性能或避免非预期结果,将能减少管道文档数量的操作尽可能少前置,同时聚合的结果中每个文档有16MB的大小限制,在聚合管道中每个阶段(总量)有100MB的内存大小限制,如果超过这个限制则需要使用选项参数{allowDiskUse:true}以启用磁盘临时存储。聚合的$match,$group阶段都可以利用索引来提高效率。

MongoDB查询计划分析[2]

MongoDB中通过cursor.explain()和aggregate([],{explain:true})来展示查询计划,下面介绍explain返回结果。

  • queryPlanner:queryPlanner显示被查询优化器选择出来的查询计划,其中winningPlan是将被执行的获胜计划,rejectedPlans是拒绝的候选计划。对于分片集合,获胜计划包括分每个访问的分片的计划信息数组。
{
   "queryPlanner" : {
      "plannerVersion" : <int>,
      "namespace" : <string>,
      "indexFilterSet" : <boolean>,
      "parsedQuery" : {
         ...
      },
      "winningPlan" : {
         "stage" : <STAGE1>,
         ...
         "inputStage" : {
            "stage" : <STAGE2>,
            ...
            "inputStage" : {
               ...
            }
         }
      },
      "rejectedPlans" : [
         <candidate plan 1>,
         ...
      ]
   }
    • stage 阶段名称。每个阶段都有每个阶段特有的信息。 例如,IXSCAN 阶段将包括索引边界以及特定于索引扫描的其他数据。 如果阶段具有子阶段或多个子阶段,则阶段将具有inputStage 或 inputStages。
    • inputStage 描述子阶段的文档。它为其父级提供文档或索引键。 如果父级只有一个子级,则该字段存在。
    • inputStages 描述子阶段的数组。子阶段为父阶段提供文档或索引键。 如果父级具有多个子节点,则该字段存在。 例如,$or 表达式或索引交集的阶段消耗来自多个源的输入。
  • executionStats:executionStats 返回的是获胜计划执行相关信息。必须在 executionStats 或 allPlansExecution 详细模式下运行explain才显示executionStats 相关信息:cursor.explain(true)/cursor.explain("executionStats")/cursor.explain("allPlansExecution")
"executionStats" : {
   "executionSuccess" : <boolean>,
   "nReturned" : <int>,
   "executionTimeMillis" : <int>,
   "totalKeysExamined" : <int>,
   "totalDocsExamined" : <int>,
   "executionStages" : {
      "stage" : <STAGE1>
      "nReturned" : <int>,
      "executionTimeMillisEstimate" : <int>,
      "works" : <int>,
      "advanced" : <int>,
      "needTime" : <int>,
      "needYield" : <int>,
      "isEOF" : <boolean>,
      ...
      "inputStage" : {
         "stage" : <STAGE2>,
         ...
         "nReturned" : <int>,
         "executionTimeMillisEstimate" : <int>,
         "keysExamined" : <int>,
         "docsExamined" : <int>,
         ...
         "inputStage" : {
            ...
         }
      }
   },
   "allPlansExecution" : [
      { <partial executionStats1> },
      { <partial executionStats2> },
      ...
   ]
}
    • executionStats 描述获胜计划完整的查询执行信息。 对于写入操作,是指将要执行修改的信息,但不会真实修改数据库。
    • nReturned 查询条件匹配到的文档数量。
    • executionTimeMillis 查询计划选择和查询执行所需的总时间(以毫秒为单位)。executionTimeMillis 对应于早期版本的MongoDB中cursor.explain() 返回的millis字段。
    • totalKeysExamined 扫描的索引条目数。totalKeysExamined 对应于早期版本的MongoDB中cursor.explain() 返回的 nscanned字段。
    • totalDocsExamined 扫描的文档数。totalDocsExamined 对应于早期版本的MongoDB中cursor.explain() 返回的 nscannedObjects字段。
    • executionStages 阶段树形式展示获胜计划完整的执行信息。即,一个阶段可以有一个inputStage或多个inputStages。
    • works 查询执行阶段执行的“工作单元”的数量。 查询执行阶段将其工作分为小单元。 “工作单位”可能包括检查单个索引键,从集合中提取单个文档,将投影应用于单个文档或执行内部记账。
    • advanced 返回到父阶段的结果数。
    • needTime 未将中间结果返回给其父级的工作循环数。 例如,索引扫描阶段可以花费一个工作周期来寻找索引中的新位置而不是返回索引关键字; 这个工作周期将计入needTime而不是advanced。
    • needYield 存储层请求查询系统产生锁定的次数。
    • isEOF 执行阶段是否已到达流的结尾。如果为true或1,则执行阶段已到达流末尾;如果为false或0,则阶段可能仍会返回结果。 例如,有限制的查询,其执行阶段包含LIMIT阶段,其中查询的输入阶段为IXSCAN。 如果查询返回超过指定的限制,LIMIT阶段将报告isEOF:1,但其基础IXSCAN阶段将报告isEOF:0。
    • inputStage.keysExamined 对于扫描索引的查询执行阶段(例如IXSCAN),keysExamined是在索引扫描过程中检查的入站和越界键的总数。 如果索引扫描由单个连续范围的键组成,则只需要检查入站键。 如果索引边界由若干键范围组成,则索引扫描执行过程可以检查越界键,以便从一个范围的末尾跳到下一个范围的开头。
    • inputStage.docsExamined 在查询执行阶段扫描的文档数。
  • allPlansExecution 包含在计划选择阶段为获胜和拒绝计划捕获的部分执行信息。仅当explain在allPlansExecution详细模式下运行时,该字段才会出现。

explain 希望看到的阶段:

Fetch+IDHACK

Fetch+ixscan

Limit+(Fetch+ixscan)

PROJECTION+ixscan

SHARDING_FILTER+ixscan

COUNT_SCAN

...

explain 不希望看到的阶段:

COLLSCAN(全表扫描),

SORT(使用sort但是无index),

不合理的SKIP,

SUBPLA(未用到index的$or),

COUNTSCAN

MongoDB中类似条件的查询会在进行判断后直接使用缓存的执行计划,所以当我们修改索引等情况下,想要立即生效最简单的办法就是清楚执行计划缓存,语法如下:db.coll.getPlanCache().clear()


参考

  1. ^官方文档 https://docs.mongodb.com
  2. ^explain详解 https://xuexiyuan.cn/article/detail/179.html?from=csdn
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值