• [技术干货] mongodump参数浅解(初版,待继续完善)
    -q 按照日期时间范围导出数据,是需要指定数据库和集合。有此特定需求是可以使用,不适合数据库全量备份。 --oplog 采用此参数备份时,方式是热备份,不影响业务。备份中产生的数据写入,会缓存在local数据库中。 备份截止时间点前的文件和动态写入的local中的文件,会一并备份。采用mongoretore进行恢复时,加上--oplogReplay即可还原到相应的备份截止时间点。备份过程中无此参数的话,因为有实时写入的数据,会造成备份文件紊乱。 另,mongodump和mongorestore是对数据是逻辑处理,性能较差。
  • mongodb 代码阅读-003 mongodb util类之Decorable
    本帖最后由 eharry 于 2018-4-15 23:55 编辑mongodb 代码阅读-003mongodb util类之Decorable在阅读mongodb源代码的时候,经常会碰到这样的函数, 以CmdCreateUser run方法为例,... ​ ServiceContext* serviceContext = txn->getClient()->getServiceContext(); AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);上面的函数 AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);一看就是一个静态函数, AuthorizationManager 可以根据 serviceContext 得到一个AuthorizationManager的对象.如果不仔细研究代码,凭借以往经验猜想的话这个函数最基本的实现,肯定是AuthorizationManager里面有一个静态map(或者是别的什么容器), 这个容器里包含了 serviceContext 和 AuthorizationManager的对应关系. 这样才能根据 serviceContext得到AuthorizationManager对象.但是,如果再仔细阅读以下AuthorizationManager的代码的话,你就会发现, AuthorizationManager类中,并没有所谓的静态容器来保存AuthorizationManager和serviceContext的对应关系. 甚至连保存serviceContext的map都没有.一般来说,AuthorizationManager和serviceContext的对应关系, 要么存在AuthorizationManager上,要么存在serviceContext上. 既然AuthorizationManager没有,那么很有可能是在serviceContext上.然而不幸的是, 仔细搜寻serviceContext代码后,并没有AuthorizationManager的存储变量, 如果再仔细看一下serviceContext的类定义文件的话,发现连AuthorizationManager的class都没有声明. 那么自然不可能存储AuthorizationManager的容器了.那么这个对应关系到底存在哪呢?所以,我们的代码分析结果还是应该返回到 AuthorizationManager::get(serviceContext); 这个函数调用上,究竟这个函数是如何工作的?搜索这个函数的定义, 找到这个函数真正的实现地方 AuthorizationManager* AuthorizationManager::get(ServiceContext* service) { return getAuthorizationManager(service).get(); }不用管 最后一个get, 直接看这个函数getAuthorizationManager const auto getAuthorizationManager = ServiceContext::declareDecoration>();然后你就会得到一个这个东西, 看着调用的地方像是个函数啊, 可以看看赋值的地方,这就是个变量啊.ServiceContext::declareDecoration 的函数定义如下: template static Decoration declareDecoration() { return Decoration(getRegistry()->declareDecoration()); }如果这个时候,你继续跟随这个东西分析下去, 十有八九都会被这段复杂的代码逻辑绕晕.所以我们先不要分析代码细节,研究一下这个赋值和调用的地方AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);const auto getAuthorizationManager = ServiceContext::declareDecoration>();首先我们看到getAuthorizationManager的参数, 是一个ServiceContext,在赋值的语句里, 它作为对象出现在赋值语句右侧. 正是调用了ServiceContext的这个特定方法,才得到了getAuthorizationManager这个变量.其次我们看到AuthorizationManager这个类型,作为赋值语句的函数参数, 出现在赋值语句的右侧. 正是ServiceContext和AuthorizationManager这两个类的配合,才得到了getAuthorizationManager这个变量.所以我们可以简单的得到一个结论 :c=a::declareDecoration>(); ​ b obj = c(a);但是这个赋值语句究竟是现有的a,b之间的关系,才可以运行赋值语句,还是说 这个赋值语句自带了定义规则的属性,这个就不得而知了.这个时候: Decoration 这个单词可以说明这一切.装饰, 在这里表示装饰模式. 而装饰模式, 就是指不改变类的情况下,通过装饰类来完成原生类的一些功能和行为的改变.所以 ServiceContext 和 AuthorizationManager, 这两个必然有一个是装饰类, 而另一个是要被装饰的对象. 查看各自类代码可知, ServiceContext 继承了 class ServiceContext : public Decorable ServiceContext的所有装饰行为都被封装到Decorable, 包括ServiceContext跟AuthorizationManager的对应关系.这样,当得到ServiceContext对象的时候,我们可以从他的父类里,拿到AuthorizationManager的对象,这样就可以得到对应关系了.注 : 为什么使用装饰模式. [*]一般来说, ServiceContext和AuthorizationManager的对应关系,一般应该封存在某个类的静态方法里, 这样代码便于理解和维护.但是在某些情况下, 这种方式不好做到. 最主要是就是类之间的依赖关系.a. 在上面那个例子中, 如果把AuthorizationManager放到ServiceContext里面, 不可避免要让ServiceContext依赖AuthorizationManager,这样在代码结构上就造成了底层依赖上层的编译逻辑.b. 不仅仅是AuthorizationManager依赖ServiceContext, 还有其他的变量,都会依赖ServiceContext, 每新增加一个依赖,都需要重新编译ServiceContext, 这样的软件架构也是不好的.c. 代码重复, 同样的依赖代码要写很多相似的代码. [*]所以一般基于上面说的逻辑,当软件中出现大规模这种结构依赖的时候, 装饰模式是一种比较好的做法. 将类的行为和依赖行为分开到不同类里面执行. 并且将依赖行为抽象化, 不用每个依赖像都重写一个函数. 简单装饰模式的实现: 1) 将依赖类, 注入到装饰模式里面, 因为依赖的是对象, 需要在装饰模式里面定义一个list,里面存储着所有的依赖对象. 这样当装饰模式创建后,可以通过注册函数将对象注入进来,得到一个装饰模式对象. 然后在其他地方调用相关函数,得到对应关系. 2) 上述模式将对象注入到装饰类,但是在某些情况下,我们并不能确定调用关系和注入关系的顺序. 或者说装饰类对象生成和注册之间的执行顺序, 所以在此基础之上, 我们将依赖类的构造函数注入到装饰类中. 这样当装饰类进行初始化的时候,可以直接调用构造函数初始化依赖类,这样就免去了注入对象的过程. 仅仅需要注入构造函数即可. 3) 注入构造函数,按照c++的特性,自然是要构造析构函数了. 4) 有了构造和析构函数,考虑到装饰类并不仅仅只保存一个依赖类, 所以为了方便程序其他地方对依赖类的操作,我们应该提供一个方便得到依赖类对象的方法. 所以可以提供一个map 如果想明白了简单装饰器的实现,那么再看mongodb这块的装饰模式实现,就不会觉得那么难以理解了.mongodb认为,你注入了这个依赖类规则,肯定是要使用的, 所以讲简单装饰器模式的第二步和第四步合并,在注入依赖规则的同时,返回了一个变量,然后又重定义了(), 只要利用这个变量加上装饰类,就可以得到依赖类的对象. 让调用看上去更像一个函数. AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);const auto getAuthorizationManager = ServiceContext::declareDecoration>();Decorable内部,并没有实现我说的通过map来保存 类名和对象的结构,而是通过 offset来给出对象地址. mongodb通过每个对象的大小,对其情况等等,计算出依赖类的地址,然后返回给客户.最后 : [*]当看到以下代码时,可以理解为, ServiceContext创建了一个std::unique_ptr, 我们可以通过getAuthorizationManager(serviceContext)去得到它. const auto getAuthorizationManager = ServiceContext::declareDecoration>(); [*]ServiceContext包含的东西,远不止代码中所显示的那么多, 或者说,主要包含的东西,都已经在装饰器内部被封装为object和一串offset了,要想知道 ServiceContext, 还是应该搜索 ServiceContext::declareDecoration函数的调用情况. [*]装饰器就是动态添加一些功能行为到原生类里面, 本文主要说了构造函数和析构函数,但可以添加的远不止这些.
  • [技术干货] MongoDB查询过程explain参数详解
    本帖最后由 Nosql_newbee 于 2018-4-14 18:37 编辑 Mongodb提供了db.collections.explain()方法来返回查询过程中的具体信息,包括查询过程中的执行统计结果和查询方案,对于比较慢的查询来说,是重要的诊断工具之一。通过explain的输出信息,可以知道查询使用了哪个所以,以及如何使用的。对于任意的查询,都可以在最后添加一个explain()。 explain命令有三种模式: · queryPlanner · executionStats · allPlan**ecution queryPlanner,在非分片模式下,explain返回下列信息: { "queryPlanner" : { "plannerVersion" : , "namespace" : , "indexFilterSet" : , "parsedQuery" : { ... }, "winningPlan" : { "stage" : , ... "inputStage" : { "stage" : , ... "inputStage" : { ... } } }, "rejectedPlans" : [ , ... ] } 包含查询优化器选择等信息: explain.queryPlanner.namespace: 字符串类型,标识查询的集合名称 explain.queryPlanner.indexFilterSet: boolen类型,标识是否使用索引 explain.queryPlanner.winningPlan: 文档类型,包含查询优化器选择的最优查询,mongodb通过一个树形结构来表示不同阶段。 explain.queryPlanner.winningPlan.stage: 字符串类型,标识 不同阶段的名字,每个阶段由一系列具体信息组成,例如,IXSCAN 阶段包括索引绑定和扫描,如果一个阶段还有一个子阶段或者多个子阶段,则包含子节点inputStage 或 inputStages explain.queryPlanner.winningPlan.inputStage: 文档类型,描述子阶段信息。 explain.queryPlanner.winningPlan.inputStages: 数组文档类型 explain.queryPlanner.rejectedPlans: 标识一组被查询优化器拒绝的候选执行计划,如果没有候选的计划,该字段为空。 对于分片集合,winningPlan 包括了每个分片组的详细信息,例如: "queryPlanner" : { ... "winningPlan" : { ... "shards" : [ { "shardName" : , , }, ... ], }, }, executionStats 返回winningPlan的具体执行信息,要想获取到该信息,explain必须执行在 executionStats 或者 allPlan**ecution模式下(默认是queryPlanner模式)在非分片模式下,explain会返回一下信息: "executionStats" : { "executionSuccess" : , "nReturned" : , "executionTimeMillis" : , "to**ey**amined" : , "totalDoc**amined" : , "executionStages" : { "stage" : "nReturned" : , "executionTimeMillisEstimate" : , "works" : , "advanced" : , "needTime" : , "needYield" : , "saveState" : , "restoreState" : , "isEOF" : , ... "inputStage" : { "stage" : , ... "nReturned" : , "executionTimeMillisEstimate" : , "key**amined" : , "doc**amined" : , "saveState" : , "restoreState" : , ... "inputStage" : { ... } } }, "allPlan**ecution" : [ { }, { }, ... ] } 该文档中返回了winningPlan的完整的执行信息 explain.executionStats.nReturned: int型,符合查询条件的文档数 explain.executionStats.executionTimeMillis: 整个查询所需要的时间,单位为毫秒 explain.executionStats.to**ey**amined: 整个查询过程扫描的索引数 explain.executionStats.totalDoc**amined: 整个查询过程中扫描的文档数 explain.executionStats.executionStages: winning plan具体的执行过程可能包含inputStage 或者inputStages explain.executionStats.executionStages.works: 执行了多少个工作单元,查询过程会分解为不同的工作单元(“works unit”),例如,检查一个索引的key值,或者查询了一个文档等 explain.executionStats.executionStages.advanced: 有多少中间结果返回 explain.executionStats.executionStages.needTime: explain.executionStats.executionStages.needYield: 存储层请求查询阶段暂停处理并产生其锁的次数。 explain.executionStats.executionStages.saveState: 查询阶段暂停处理并存储其当前执行状态的次数 explain.executionStats.executionStages.restoreState: 查询阶段恢复一个执行状态的次数 explain.executionStats.executionStages.isEOF: 标识执行阶段是否结束,1为结束,0表示该阶段还有结果需要返回 explain.executionStats.executionStages.inputStage.key**amined: 在查询过程中,检查索引的总数 db.keys.find( { x : { $in : [ 3, 4] } } ).explain( "executionStats" ) 例如以上查询结果返回为3,查询过程中会检查索引3,4。然后检查5。总共检查了3次 explain.executionStats.executionStages.inputStage.doc**amined: 查询过程中扫描文档数 serverInfo "serverInfo" : { "host" : , "port" : , "version" : , "gitVersion" : }
  • [技术干货] MongoDB存储引擎WiderTiger介绍-01
    从MongoDB在3.2版本中进行了更改:WiredTiger存储引擎是从MongoDB 3.2开始的默认存储引擎。对于现有的部署,如果不指定--storageEngine或storage.engine设置,MongoDB 3.2可以自动确定用于在--dbpath或storage.dbPath中创建数据文件的存储引擎。 WiredTiger针对写入操作使用文档级并发控制。因此,多个客户端可以同时修改集合中的不同文档。 对于大多数读写操作,WiredTiger使用乐观并发控制。 WiredTiger仅在全局,数据库和集合级别使用意向锁。当存储引擎检测到两个操作之间发生冲突时,会引发写冲突,导致MongoDB透明地重试该操作。 对于一些全局性操作(通常涉及多个数据库的短暂操作)仍需要全局“实例范围”锁定。其他一些操作(如删除集合)仍然需要独占数据库锁定。1.1 快照和检查点 WiredTiger使用MultiVersion并发控制(MVCC)。在每一个操作开始时,WiredTiger提供个特性时间点快照的数据。快照代表了内存数据的一致视图。 在写入磁盘时,WiredTiger将一个快照中的所有数据以一致性(对于磁盘的全部的数据文件)的方式写入到磁盘中。最新的持久的数据可以作为数据文件中的检查点。检查点确保数据文件在最后一个检查点之前保持一致;即检查点可以充当恢复点。 MongoDB将WiredTiger配置为以60秒或2G的日志数据为间隔创建检查点(即将快照数据写入磁盘)。 在写入新的检查点期间,以前的检查点仍然有效。因此,即使MongoDB在编写新的检查点时终止或遇到错误,在重新启动时,MongoDB可以从最后一个有效检查点恢复 当WiredTiger的元数据表被原子更新为引用新的检查点时,新的检查点变得可访问且永久。一旦可以访问新的检查点,WiredTiger将从旧检查点释放页面。 使用WiredTiger,即使没有日志记录,MongoDB也可以从上一个检查点恢复;但是,要恢复上次检查点后所做的更改,请使用日记功能运行。1.2 日志 WiredTiger使用提前写入事务日志与检查点相结合来确保数据持久性。 WiredTiger日志保存检查点之间的所有数据修改。如果MongoDB在检查点之间退出,它将使用日志重放自上一个检查点以来修改的所有数据。有关MongoDB将日志数据写入磁盘的频率的信息,请参阅日记过程。 WiredTiger日志使用快速压缩库进行压缩。要指定备用压缩算法或不压缩,请使用storage.wiredTiger.engineConfig.journalCompressor设置。 对于独立实例,不使用日志意味着当MongoDB在检查点之间意外退出时将丢失一些数据修改。对于副本集的成员,复制过程可以提供足够的持久化保证。 1.3 压缩 借助WiredTiger,MongoDB支持所有集合和索引的压缩。压缩最大限度地减少存储使用,但需要增加额外的CPU。 默认情况下,WiredTiger使用快速压缩库对所有集合进行块压缩,并对所有索引进行前缀压缩。 对于集合,也可以使用zlib进行块压缩。要指定备用压缩算法或不压缩,请使用storage.wiredTiger.collectionConfig.blockCompressor设置。 对于索引,要禁用前缀压缩,请使用storage.wiredTiger.indexConfig.prefixCompression设置。 在收集和索引创建过程中,压缩设置也可以按收集和按索引进行配置。请参阅指定存储引擎选项和db.collection.createIndex()storageEngine选项。 对于大多数工作负载,默认的压缩设置可以平衡存储效率和处理要求。 WiredTiger日志也是默认压缩的。有关日记压缩的信息,请参阅日记帐。 1.4 内存使用 借助WiredTiger,MongoDB既利用WiredTiger内部缓存,又利用文件系统缓存。版本3.2中更改:从MongoDB 3.2开始,缺省情况下,WiredTiger内部缓存将使用以下两者中的较大者: RAM的60%减去1 GB, 或 1 GB。 对于具有高达10 GB RAM的系统,新的默认设置小于或等于3.0默认设置(对于MongoDB3.0,WiredTiger内部高速缓存使用1 GB或一半的已安装物理RAM,以较大者为准)。对于RAM大于10 GB的系统,新的默认设置大于3.0设置。通过文件系统缓存,MongoDB自动使用WiredTiger缓存或其他进程未使用的所有空闲内存。文件系统缓存中的数据是压缩的。要调整WiredTiger内部缓存的大小,请参阅storage.wiredTiger.engineConfig.cacheSizeGB和--wiredTigerCacheSizeGB。避免将WiredTiger内部缓存大小增加到默认值以上。 参考文档:https://docs.mongodb.com/v3.2/core/wiredtiger/
  • MongoDB的CRUD操作
       CURD代表创建(Create)、更新(Update)、读取(Read)和删除(Delete)数据库文档的操作。 以mongoshell 举例。创建操作创建或者说**操作,是将一个数据库文档(相当于SQL中的记录)添加到 一个 数据库集合中(相当于SQL中的表)。如果 数据库集合不存在,那么使用创建操作会默认创建一个数据库集合Mongodb提供以下方式 创建文档。db.collection.insert()db.collection.insertOne() 3.2 版本新增db.collection.insertMany() 3.2版本新增创建操作针对一个集合,所有单个文档的写操作是原子级别的。如下:13714一次可以创建单个文档,也可以创建多个文档。db.collection.insertOne() 创建单个文档:创建单个文档到inventory 数据集合, 如果文档中没有定义_id 字段,会默认生产一个ObjectId 作为主键。返回一个文档,包含新创建文档的 _id 字段和对应的值。 为了验证创建, 可以通过查询操作进行查询。[code]db.inventory.insertOne(   { item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } })db.inventory.find( { item: "canvas" } )[/code]13715db.collection.insertMany() 创建多个文档:传入多个文档到数据集合,传入一个文档数组格式。下面的例子创建三个新的文档到inventory 数据集合。返回一个文档,包含新创建文档的 _id 字段和对应的值。为了验证创建, 可以通过查询操作进行查询。[code]db.inventory.insertMany([   { item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },   { item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },   { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }])db.inventory.find( {} )[/code]13716读取操作读取操作是从一个数据集合中获取某个文档。Mongodb提供以下方式 读取文档:db.collection.find()你可以定义查询的过滤条件。如下13717更多了解参考文档:[mongodb 查询命令及参数详解(1)](http://forum.huaweicloud.com/thread-7842-1-1.html)更新操作更新操作是修改数据集合中存在的文档。Mongodb提供以下方式 更新文档。db.collection.update()db.collection.updateOne()3.2 版本新增db.collection.updateMany()3.2 版本新增db.collection.replaceOne()3.2 版本新增更新操作针对某一个数据集合,所有单个文档的写操作是原子级别的。你可以通过过滤条件,来筛选需要更新的文档。更新操作的过滤条件与读取操作的过滤条件语法一样。另外需要定义更新操作,例如$set 来修改字段的值。如下:13718使用更新操作,需要采用下面的格式。$set 操作,会在更新字段不存在时,创建该字段。{  
  • 【MongoDB】MongoDB分片的片键选择-01
    本帖最后由 Mongo_奇 于 2018-4-16 19:40 编辑【MongoDB】MongoDB分片集群的片键选择: MongoDB有一个相当重要的功能就是它的分片集群部署模式,那么MongoDB是如何决定数据在各个分片上的分布呢?这就引出了这里要讲的内容:分片集群的片键。 如何设定片键: 想要使用片键,首先需要对数据库开启分片: sh.enableSharding("") 选择分片的片键: sh.shardCollection( namespace, key ) 选择片键需要考虑的因素: 片键基数: 片键基数指的是划分数据块的能力。举个例子,假如要记录一个省所有考生的高考成绩,如果以成绩作为片键进行范围分片,那存储较高成绩记录的分片的数据量必然要远远小于存储平均成绩左右记录的分片的数据量,存储数据最多的这个分片就会成为瓶颈。这时以考生的考号作为片键就更有利于数据的均匀分布。 写分布: 用户往往会期望数据均匀分布于各个分片上,如果以一个单调递增的值作为片键,那么最终数据往往只会往一个分片上写入。 查询分发: 同样的,大多数情况下我们也希望读操作均匀的分布于集群的分片 查询隔离: 如果分片集群的查询要通过查询所有的分片才能返回结果的话,代价也往往是很高的。考虑上文中片键基数的例子:如果把考生的考号作为片键虽然可以做到写分布均匀,但是如果想查询某个分数的所有考生数据就需要遍历所有的分片了。如果此时的分片很多,那么代价其实还是很高的。如果这种查询很多,就要考虑另外一种片键了。现在我们制作一个复合片键({考生分数,考生的考号}),那么同样的分数必然只处于相近的几个分片上,同时考生的考号又增加了片键基数,算是比较平衡了写入和查询的隔离。
  • [技术干货] mongodb与mysql的对比
    概观关系数据库几十年来一直是企业应用程序的基础,自1995年MySQL发布以来,它一直是一种流行且廉价的选择,特别是作为早期Web应用程序的普遍LAMP堆栈的一部分。今天,现代企业正在考虑更好的方式来存储和管理他们的数据 - 无论是为了获得更好的客户洞察力,适应不断变化的用户期望,还是通过新的应用程序和商业模式将竞争对手推向市场。因此,推动早期关系数据库开发的许多假设已经发生了变化: [*]要求更高的开发人员生产力和更快的上市时间,传统的僵化的关系数据模型和瀑布式开发的单片应用程序让位于敏捷方法,微服务和全栈开发,将发布周期从几个月,几年压缩到几天和几周。 [*]需要管理新的,快速变化的数据类型的大规模增长 - 由新型Web,移动,社交和物联网应用程序生成的结构化,半结构化和多态数据。 [*]全面转向分布式系统和云计算,使开发人员能够利用随需应变,高度可扩展的计算和存储基础架构,并且能够为全球任何地点的工作和观众提供服务,同时满足全新的监管需求数据主权。 因此,为了解决新应用程序的需求并实现现有工作负载的现代化,出现了像MongoDB这样的非关系型数据库。MongoDB 4.0将会在2018年夏季,计划的支持多文档ACID事务,将使开发人员更容易使用。什么是MySQL?MySQL是一个流行的开源关系数据库管理系统(RDBMS),由Oracle公司开发,分发和支持。像其他关系数据库一样,MySQL将数据存储在表中,并使用结构化查询语言(SQL)进行数据库访问。在MySQL中,您可以根据需求预先定义数据库模式,并设置规则来管理表中字段之间的关系。模式中的任何更改都需要执行迁移过程,以使数据库脱机或显着降低应用程序性能。什么是MongoDB?MongoDB是由MongoDB,Inc.开发的开源非关系数据库。MongoDB将数据存储为称为BSON(二进制JSON)的二进制表示形式的文档。相关信息通过MongoDB查询语言一起存储以便快速查询访问。字段可以因文档而异; 不需要向系统声明文档的结构 - 文档是自描述的。如果需要将新字段添加到文档中,则可以在不影响集合中的所有其他文档的情况下创建该字段,而无需更新中央系统目录,也不需要使系统脱机。或者,可以使用模式验证来对每个集合实施数据管理控制。MongoDB的文档数据模型自然映射到应用程序代码中的对象,使开发人员可以轻松学习和使用。文档使您可以轻松地表示层次关系来存储数组和其他更复杂的结构。为10种以上语言提供了原生的,惯用的驱动程序 - 社区已经构建了数十种语言 - 支持即时查询,实时聚合和丰富的索引,以提供强大的编程方式来访问和分析任何结构的数据。由于文档可以汇集相关数据,否则这些数据将在关系模式中通过单独的父 - 子表建模,因此MongoDB的原子单文档操作已经提供了符合大多数应用程序的数据完整性需求的事务语义。一个或多个字段可以在单个操作中写入,包括更新多个子文档和数组的元素。MongoDB提供的保证确保在文档更新时完全隔离; 任何错误都会导致操作回滚,以便客户端收到文档的一致视图。预定于2018年夏季的MongoDB 4.0将增加对多文档事务的支持,使其成为唯一一个将传统关系数据库的ACID保证,文档模型的速度,灵活性和强大功能与智能分布式系统设计来扩展并将数据放在需要的地方。通过快照隔离,事务将提供全局一致的数据视图,并执行全有或全无执行来维护数据完整性。MongoDB中的事务就像开发人员在MySQL中熟悉的事务一样。它们将是多语句,具有类似的语法(例如: start_transaction和commit_transaction),因此对于任何具有交易经验的人员都可以轻松添加到任何应用程序中。与MySQL和其他关系数据库不同,MongoDB建立在分布式系统架构上,而不是单一的单节点设计。因此,MongoDB提供了开箱即用的自动分片功能的横向扩展和数据本地化功能,以及具有高可用特性的副本集。术语和概念MySQL中的许多概念在MongoDB中都有类似的特征。下表概述了MySQL和MongoDB的通用概念。MySQLMongoDBACID事务ACID事务*[tr=rgb(248, 248, 248)]TableCollectionRowDocument[tr=rgb(248, 248, 248)]ColumnFieldSecondary IndexSecondary Index[tr=rgb(248, 248, 248)]JOINsEmbedded documents, $lookup & $graphLookupGROUP_BYAggregation PipelineACID事务计划为MongoDB 4.0 *功能比较和MySQL一样,MongoDB提供了一套丰富的特性和功能,远远超出了简单的NoSQL数据存储所提供的功能和功能。MongoDB具有丰富的查询语言,功能强大的二级索引(包括文本搜索和地理空间),强大的数据分析聚合框架,分面搜索,图形处理等等。使用MongoDB,您还可以在关系数据库中使用更多不同数据类型的这些功能,并且大规模使用。MySQL的MongoDB的NoSQL数据存储开源是是是[tr=rgb(248, 248, 248)]ACID事务是是* 1没有灵活丰富的数据模型没有是部分:架构灵活性,但仅支持简单的数据结构[tr=rgb(248, 248, 248)]模式管理是是没有expressive joins,分面搜索,图表查询,强大的聚合是是没有[tr=rgb(248, 248, 248)]原生语言驱动支持没有是没有数据局部性的水平扩展没有是部分:不控制数据局部性[tr=rgb(248, 248, 248)]对接分析系统和BI系统是是没有企业级安全和成熟的管理工具是是没有[tr=rgb(248, 248, 248)]数据库作为所有主要云端的服务是是没有[*]1预定MongoDB 4.0,2018年夏季 查询语言MySQL和MongoDB都有丰富的查询语言。可以在MongoDB文档中找到完整的语句列表。MySQL的MongoDB的INSERT INTO用户(user_id,年龄,状态)VALUES('bcd001',45,'A')db.users.insert({ user_id:'bcd001', 年龄:45岁, 状态:'A'})[tr=rgb(248, 248, 248)]SELECT * FROM用户db.users.find()更新用户SET状态='C'年龄> 25岁db.users.update( {年龄:{$ gt:25}}, {$ set:{status:'C'}}, {multi:true})为什么使用MongoDB而不是MySQL?各种规模的组织都在采用MongoDB,因为它使他们能够更快地构建应用程序,处理高度多样化的数据类型,并在规模上更高效地管理应用程序。随着MongoDB文档自然地映射到现代的面向对象的编程语言,开发被简化了。使用MongoDB将删除将代码中的对象转换为关系表的复杂对象关系映射(ORM)层。MongoDB灵活的数据模型也意味着您的数据库模式可以随业务需求而变化。MongoDB也可以扩展到多个分布式数据中心内部,从而提供以前在像MySQL这样的关系数据库中无法实现的新的可用性和可伸缩性级别。随着您的部署在数据量和吞吐量方面的增长,MongoDB无需停机即可轻松扩展,并且无需更改应用程序。相比之下,为了达到MySQL的规模,往往需要大量的定制工程工作。JSON文档的开发人员生产力事实证明,将数据作为灵活的JSON文档而不是刚性的行和列处理,可以帮助开发人员更快地移动。从关系型数据库迁移到MongoDB之后,找到能够将开发周期缩短4倍或5倍的团队并不困难。为什么是这样?: [*]文件是很自然的文档以与应用程序相同的方式表示数据。与关系数据库的表格行和列不同,数据可以使用数组和子文档进行结构化 - 与应用程序分别表示数据相同,分别作为列表和成员/实例变量。这使得开发人员可以更简单快速地模拟应用程序中的数据如何映射到存储在数据库中的数据。 [*]文件是灵活的每个文档都可以存储具有其他文档不同属性的数据。例如,考虑一个产品目录,其中存储男士服装细节的文档将存储来自存储平板电脑细节的文档的不同属性。这是一种通常称为“多态性”的属性。使用JSON文档,我们可以在需要时添加新属性,而无需更改集中式数据库模式。在最坏的情况下,这最多会导致关闭数据库中的停机时间显着增加。灵活性文档带来的开发人员可以更轻松地处理由现代移动,Web和物联网应用程序生成的半结构化和非结构化数据。 [*]文件使应用程序更快。对于存储在单个文档中的实体数据,而不是跨多个关系表分布,数据库只需要读取和写入一个地方。将对象的所有数据放在一个地方也使开发人员更容易理解和优化查询性能。 正是出于这些原因,MySQL和其他关系数据库已经增加了对JSON的支持。但是,简单地添加JSON数据类型并不会将开发人员的生产力优势从文档数据库带给MySQL。为什么?因为MySQL的方法可能会降低开发人员的生产力,而不是改进它。考虑以下: [*]专有扩展:查询和操作JSON文档的内容需要使用单独的MySQL特定的SQL函数来访问值,这对大多数开发人员来说并不熟悉。另外,它们不受第三方SQL工具(例如BI平台,数据仓库连接器,ETL和ESB管道等)的支持或认可。 [*]MongoDB与MongoDB有何不同: MongoDB API被广泛理解,并被行业标准工具和连接器所采用。几家大型供应商数据库公司甚至自己也采用了MongoDB API。 [*]传统关系开销:即使有JSON支持,MySQL用户仍然与多层SQL /关系功能绑定,以与JSON数据 - 低级JDBC / ODBC驱动程序和对象关系映射程序(ORM)进行交互。对于有经验的MySQL开发人员来说,这些层可能是熟悉的,但对于许多其他开发人员来说,他们想通过API来与文档和数据进行交互,而这些API对于他们的编程语言来说是自然和惯用的,这些层会带来很高的学习开销 对于性能和查询效率来说,ORM通常也很难被优化 - 即使对于有经验的关系型开发人员也是如此。另外,JSON数据的查询优化统计信息比常规关系数据类型的查询优化统计信息更加有限。 [*]MongoDB与MongoDB的不同之处在于: MongoDB驱动程序在开发人员使用的编程语言中习惯于自然的方法和函数中实现。 [*]复杂数据处理:当使用JSON数据时,MySQL驱动程序不具备将JSON正确和精确地转换为应用程序使用的有用本机数据类型的功能。这包括不同类型的数值(例如浮点,64位整数,小数)时间戳和日期,或Java中的映射或列表或Python中的字典或列表。相反,开发人员必须在他们的应用程序中手动转换基于文本的JSON,从而失去了在不同文档中使用多个数据类型的字段(多态性)的能力,并且使值的计算,排序和比较变得困难且容易出错。 [*]MongoDB如何不同: MongoDB及其驱动程序使用的二进制编码JSON(BSON)支持常规基于文本的JSON不支持的高级数据类型。 [*]没有数据治理: MySQL没有提供本机制来验证在数据库中**或更新的JSON模式,因此开发人员需要添加应用程序或数据库端功能以对数据应用治理控制。 [*]与MongoDB有什么不同: 基于JSON Schema IETF标准的Schema验证允许开发人员和DBA为每个MongoDB集合定义和实施规定的模式结构。 [*]架构刚性: MySQL用户仍然需要为常规关系数据定义架构。如果模式随后被修改以适应新的应用程序需求,则该表针对某些操作被锁定,直到现有数据被复制到新模式中,这就要求在模式迁移期间应用程序停顿。 [*]MongoDB的不同之处:开发人员和数据库管理员可以将完全动态模式的灵活性与某些应用程序所需的治理控制相结合,而不是只存储数据库中的所有数据。 用户通过MySQL选择MongoDB正如下面的例子所说明的,MongoDB在MySQL上的选择是由对开发人员生产力,应用程序性能和规模的彻底改进所驱动的: [*]百度于2012年开始使用MongoDB,在达到性能和可伸缩性限制后,最初从MySQL迁移其用户地址簿服务。现在,超过100种不同的产品和服务由运行在650节点集群上的MongoDB提供支持,部署在多个数据中心内,存储超过1PB的数据。MySQL灵活的文档数据模型可以扩展MongoDB的分布式设计和开发人员的生产力。 [*]Experian Health选择MongoDB作为MySQL和其他关系数据库的动力,为它的通用标识管理器提供支持,该标识管理器是公司用于唯一识别医疗保健客户的新应用程序。选择MongoDB是因为其灵活的数据模型,可扩展性,强大的性能和总体成本。在关系数据库上开发Universal Identity Manager意味着Experian Health开发人员需要执行多达10个SQL连接才能正确匹配患者的身份。使用MongoDB允许公司简化其模式以消除复杂性; 大幅减少查询次数; 提高性能; 并随着数据量的增加而简化增长。 [*]Viacom媒体网络,MTV,喜剧中心,Nickelodeon和其他几十个品牌的主场,在从MySQL迁移后,在MongoDB上构建了大量的轮询,投票和数据收集服务。MongoDB灵活的文档数据模型,横向扩展设计和丰富的聚合流水线使Viacom能够大规模捕获和分析数据。 [*]生物技术巨头Thermo Fisher 将从AWS Aurora上的MySQL迁移到MongoDB以及完全托管的Atlas数据库即服务后实验时间从几天缩短到几分钟。除了以40倍以下的代码提供6倍的性能以外,MongoDB还有助于降低应用程序的架构复杂性。 MongoDB的常见用例是什么?MongoDB是一个通用数据库,用于各种用例。MongoDB最常见的用例包括, 单一视图,物联网,移动,实时分析,个性化,目录和内容管理。随着多文档交易的增加,MongoDB将更加容易处理一系列的用例。MySQL何时更适合?虽然许多组织已经成功从RDBMS迁移到MongoDB,但您不能将MongoDB作为以关系数据模型和SQL为基础构建的遗留应用程序的替代品。然而,组织正从将关键任务,创收应用现代化到MongoDB中受益。例如,思科将其电子商务平台从传统关系数据库迁移到MongoDB。因此,它通过降低8倍延迟并消除系统升级期间的停机时间,改善了客户体验。其开发团队可以更快地构建和发布新的应用程序,而公司的电子商务平台可以利用云计算所带来的业务敏捷性。想要了解更多?将RDBMS获取到MongoDB迁移指南由于我们今天构建和运行应用程序的方式,以及数据源和用户负载的增长,关系数据库正在被超越其极限。为了应对这些挑战,像MTV和思科这样的公司已经成功地从关系数据库迁移到MongoDB。在本白皮书中,您将了解到: [*]一步一步如何从关系数据库迁移到MongoDB。 [*]相关的技术考虑因素,例如关系数据模型和文档数据模型之间的差异以及对模式设计的影响。 [*]索引,查询,应用程序集成和数据迁移。
  • [技术干货] 什么是分片集群(Sharding Cluster)
    本帖最后由 lipo 于 2018-4-8 22:06 编辑什么是分片集群 分片集可以说是MongoDB的高级形态,它里面存储数据的部分由副本集组成,比如每个片都是一个副本集,存储元数据(metadata)的config也是一个副本集,这样集群便具有了副本集的高可用,高容灾性。下图为一个典型的三分片副本集,图中每个蓝色块均可以理解为一个独立的数据库节点。 13690· 一个典型的 3 Shard分片集 分片集的应用场景:从图中不难理解,分片集对比副本集的优势,之前由一个副本集承担的读写任务,可以同时由三个分片共同承担。因此,分片集主要的应用场景为以下几个方面: [*]磁盘资源遭遇瓶颈 [*]写需求超过单个MongoDB节点的写服务能力 [*]活跃的数据集合超出单机内存容量,导致很多请求要从磁盘读取数据,影响性能 分片集的成员: [*]mongos mongos可以看做是副本集的入口和出口,mongos本身不存储任何数据,用户访问一个分片集群,做增删改查各种命令,都是通过mongos进行的,用户可以完全不用感知集群的其他成员组成,mongodb会帮你协调好一切。一般一个应用程序使用一个mongos,mongos本身不存储任何数据。 [*]shard shard本身是一个副本集,既然是副本集便要存储数据,用户使用分片集的时候,**的数据均存储在shard中,如果对目的数据**的集合不做任何限制,mongodb默认不会将此集合存储到多个分片,会全部存储在primary shard上。对集合开启分片设置后,对此集合的**和读取,则会均分到各shard上进行。 [*]config config本身是一个副本集,很明显config内也存储着数据,它里面存储的是元数据(metadata),元数据,通俗的说,就是记录我们真实**数据的“账本数据”,也就是说,元数据包含了我们设置的数据库用户、角色信息,更为关键的是,元数据记录了我们的数据在各分片的分布,这样当新数据**请求通过mongos下发后,config可以知道将新数据**哪个分片,当读取请求通过mongos下发到达后,config可以告诉mongos去哪个分片可以读到想要的数据。 [*]就各角色的功能,通俗一些的来说的话,如果把我们的数据比做一条鱼,那么我们有一条大鱼,由于太大了,要把鱼头,鱼身,鱼尾巴,分别放在仓库shard1,shard2,shard3中。放好以后,我们记性不太好,得把鱼头鱼身鱼尾巴到底放到哪个仓库去了,记在一个小本本上,这个小本本就是ConfigServer。如果发生查询操作,就像当前来了一个客户(Client),要买鱼头,客户直接去找我们任命的销售员(Mongos),销售员(Mongos)去查小本本(ConfigServer),然后查到鱼头放在仓库Shard1,就去Shard1取到鱼头,交给用户(Client)。
  • MongoDB 分片集群balancer浅谈
    本帖最后由 danglf 于 2018-4-8 20:24 编辑MongoDB 分片集群balancer浅谈本文基于MongoDB 3.2系列, 最新版本的MongoDB的balancer流程,应该会和3.2有不一致的地方。在开始之前,先说几个基本的概念:Shard: 分片,存储数据,提供高可用性和数据的一致性。分片集群中,每个shard一般都是一个复制集。mongs:客户端应用程序直接操作分片的接口。查询路由处理和定位操作到分片中并返回相关数据到客户端。一个分片集群包含多个查询路由来划分客户端的请求压力。configservers:配置服务器,存储集群中的元数据。这些数据包含集群数据到分片的映射。查询路由使用这些元数据定位操作到明确的分片中。共享集群需要有3台配置服务器。MongoDBbalancer 是一个运行在mongos中的后台线程, 该线程的主要作用就是监控shard上的chunk数量 ,如果发现某个shard上的Chunk达到一定的数量,则balancer会长期自动的将chunk数量迁移到其他shard,保证所有shard拥有的chunk数量基本一致。Balancer的整个运行过程对用户和应用完全是透明的,但是运行过程中,对整个集群的性能有一定的影响。 13688 任何一个集群中的mongos实例可以触发一次平衡过程, 当一个balancer进程激活的时候, 负责本次过程的mongos 节点, 会通过修改config数据库中的一个文档来获取锁, 每次都只有mongos负责一次balance。 Chunk 迁移过程可能会对集群的带宽和性能有一定的影响,, balancer一般通过如下方式来最小化这种影响:一次只迁移一个Chunk只有等shard 之间的chunk数量达到一定的门限值之后, 才会启动。另外管理员也可以零时的关闭balancer或者指定balancer的影响时间窗。当新加入一个shard到集群中的时候, 会导致一个不平衡, 因为新的shard上面没有任何的chunk, 所有Mongodb 开始将数据迁移到新的shard的时候,会花费一定时间。当把一个shard 从一个集群中移除后, 会发生类似的过程, balancer需要花费一定时间,把这个shard上的数据重分布到其他shard, 所以在移除shard的过程中,一定不要关闭被移除的服务器。 Chunk 迁移的大概流程: 1 balancer 首先向源shard发送一个moveChunk命令。2源shard内部开始数据迁移, 在迁移的整个过程中,对于该chunk的写入操作到落到源shard上面, 源shard接受所有写请求。3目标shard会建立数据索引。4目标shard会向源shard请求该chunk对应的文档,然后开始接受数据拷贝。5当接受到了该chunk的最后一个chunk,目标shard启动了一个同步过程,以便确保在迁移过程中的数据也都同步过来。6当同步过程结束后, 源shard会连接到config数据库, 然后更新下集群的元数据信息,这些信息包括了最新的chunk分布数据。7当源shard完成了元数据的更新后, 一旦该chunk上面没有打开的游标了, 源shard将会删除该chunk中的文档。迁移过程的限制 为了最小化平衡对集群的影响,balancer 触发条件有一定的限制,只有当多个shard之间(如果「拥有最多数量chunk的shard」与「拥有最少数量chunk的shard」的差值超过某个阈值,就会触发chunk迁移)到了一定程度才会触发迁移: 13689 异步chunk迁移清理为了迁移一个shard上的多个chunk,balancer一次迁移个chunk, 尽管如此, balancer不需要等待当前迁移过程的删除阶段结束后再去开启下一个chunk的迁移。这种方式可以加速对于那种非常不均衡集群的迁移。
  • [技术干货] Mongodump浅解(3.2版本)
    本帖最后由 叶亮 于 2018-4-8 20:38 编辑原文:https://docs.mongodb.com/v3.2/reference/program/mongodump/index.html 摘要 mongodump命令,用于数据库内容的导出(二进制),可以应用于mongod实例和mongos实例。 对于基于查询需求的数据转存,或者系统间的数据同步,或者单机的数据转存等,mongodump和mongorestore结合起来,可以作为完整备份方案的一部分。 然而,就集群和副本集来说,若要使用mongodump和mongorestore作为完整的备份方案,那么这两个工具命令仍然存在些许不足的地方。 命令行为 1,数据排除——mongodump命令,导出的备份文件中,不包含本地数据库的内容。 2,它仅捕获数据库中的文档数据,不备份索引数据。因此,用mongorestore或者mongod恢复后,必须进行索引重建。 版本兼容 版本2.2以后mongodump备份的数据,不适用于更早版本的mongod命令。因此,要避免使用新版的mongodump去备份旧版的数据库数据。 数据读取优先策略 1,副本集实例 版本3.2.0的修改:连接副本集时,--host参数指定的一个或多个目标,会影响到mongodump的数据读取策略。 如果--host的参数值,是以副本集的名字开头,那么mongodump会默认从副本集的主节点读取数据进行备份。如下: --host "replSet/rep1.example.net:27017,rep2.example.net:27017,rep3.example.net:27017" 如果--host的参数值,包含了一组mongod实例的信息,但不以副本集的名字开头。那么mongodump会默认从最近的节点读取数据进行备份。如下: --host "rep1.example.net:27017,rep2.example.net:27017,rep3.example.net:27017" 2,集群实例 版本3.0.5的修改:对于分片为副本集的集群实例,在mongs实例上运行mongodump时,不再优先从secondary节点读取数据。 对于集群,为--host参数指定host名称,mongodump从集群中每个副本集的主节点读取数据。 集群中没有分片的数据集合保存在主节点上,mongodump从主节点上读取还未分片的数据。 *每个数据库,都有自己的主分片。 文件覆盖 如果文件存在,mongodump覆盖已存在的文件。默认输出在mongo目录的dump文件夹下。 数据压缩处理 对于副本集实例,用的是WiredTiger存储引擎。mongodump输出的是未压缩的数据。 工作集 mongodump会影响数据库性能。如果数据大于系统内存,会导致内存溢出。 访问 在一个可访问的MongDB上运行mongodump,必须要对每个数据库有find权限。内嵌的备份角色,提供了对所有数据库的备份权限。 版本3.2.1修改:备份角色添加了对system.profile的备份权限。该文件生命周期存在于备份归档的过程中。而在此之前的备份过程,用户需要专门对该部分集合进行读取。
  • Mongodb查询中游标的使用及相关知识
    本帖最后由 Nosql_newbee 于 2018-4-6 17:03 编辑 游标的使用: MongoDB中,db.collection.find()方法返回一个游标,你可以通过迭代游标来访问文档的内容,在mongo shell中如果没将返回的cursor赋予局部变量(用var定义的变量),游标会自动迭代数据,默认为20行,这就是直接在shell中执行db.user.find()的结果。将返回结果赋予局部变量就可以手动的迭代访问cursor中的数据了。 首先在数据库中**测试数据 for(i=0;i100;i++){db.user.insert({"x":i});} var myCursor = db.user.find(); 可以通过next()方法来访问游标中数据 while(myCursor.hasNext()){ print(tojson(myCursor.next())); } hasNext()检查是否有后续结果存在。 还可以通过forEach()来迭代cursor访问文档, myCursor.forEach(printJson); https://docs.mongodb.com/manual/reference/method/#js-query-cursor-methods 可以在这个网址查看更多的cursor方法。 调用find时,shell并不立即查询数据库,而是等待真正开始要求获得结果时才发送查询,这样在执行之前可以给查询附加额外的选项,几乎游标对象的每个方法都 返回游标本身,这样就可以按任意顺序组成方法链。例如下面几种方法的表达式等价的: var myCursor = db.user.find().sort({"x":1}).limit(1).skip(10); var myCursor = db.user.find().limit(1).sort({"x":1}).skip(10); var myCursor = db.user.find().skip(10).limit(1).sort({"x":1}); 此时,查询还没有真正的执行,所有这些函数都只是构造查询,现在进行如下操作, myCursor.hasNext() 这时,查询被发往服务器。shell立刻获得前100个或前4M的数据(两者之间较小的),这样下次调用next()就不必再次链接服务器获取结果了,客户端使用完第一组数据时,shell会再一次联系数据库,使用getMore请求提取更多的结果。getMore请求包含一个查询标示符,项数据查询是否还有更多的结果,这个过程会一直持续到游标耗尽或者结果全部返回。 limit,skip和sort 要限制结果数量,可在find后使用limit函数,例如,只返回3个结果,可以这样限制 db.user.find().limit(3) 要是匹配的结果不到3个,则返回匹配数量的结果。limit指定的上限,skip与limit类似 db.find().skip(3) 该操作会忽略前三个匹配的文档,然后返回剩余的文档,如果集合中能匹配的文档少于3个,则不会返回任何文档。 sort接受一个对象作为参数,这个对象是一组键/值对,键对应文档的键名,值代表排序的方向。排序的方向1(升序),-1(降序),如果指定了多个键,则按照这些键被指定的顺序逐个排序,例如,按照"username"升序,按照"age"降序,可以这样写 db.user.find().sort({"username":1,"age":-1}) 这三个方法组合使用,对于分页非常有用,例如在线商店,要显示商品,每页50个,按照价格降序排列,可以这样写: db.user.find({"name":"mp3"}).limit(50).sort({"price":1}) 当用户点击下一页时, db.user.find({"name":"mp3"}).limit(50).sort({"price":1}).skip(50) 然而,skip过多的结果会导致性能问题。
  • [技术干货] Mongodb 版本升级与降级
    几年前mongodb云服务还未普及,许多客户都是自己购买虚拟机,然后再在虚拟机上搭建自己的mongodb 服务,自己运维mongodb,这是前些年大部分客户的业务场景。最近Mongodb 版本迭代数据越来越快,这不自己的版本才刚熟悉起来,可上官网一看,官网上最新的版本早已超出自己运营的版本好几代了,最新的版本又是各自新特性,各种性能的提高,看的心痒痒,要不咱的老版本也升级下?下面就详细说说升级的准备工作和步骤以及怎样确认升级是否成功,如果一旦升级失败,怎么降级来保障业务不受处理 升级前的准备工作先确认目前业务运营的mongodb的版本,在mongodb二进制目录下执行mongod --version,输出结果中有db version字段,这个字段显示的就是你当前的mongodb版本。然后确认下你想升级的mongodb版本。如果工作版本和目标版本相差比较大,那就必须一步一步的向上升级,最后达到目标版本。例如目前工作的版本是3.0,目标版本是3.6。那就必须先从3.0升级到3.2,再从3.2升级到3.4,最后在从3.4升级到3.6。在官网可以查到具体版本之间的升级,下图左面就是mongodb各个版本之间的关系了。13501 升级步骤 假设目前我们的工作版本是3.2,我们想升级的版本是3.4。我们点击Release Note for MongoDB 3.4,找到Upgrade Procedures章节13502Upgrade Procedures章节按照mongodb部署的三种形态做了区分,不同形态的升级方式不一样,我们先确认自己的部署形态然后做查看相应的升级章节(3.2升级到3.4的步骤详情可以参考我的前一篇文章: http://forum.huaweicloud.com/thread-7637-1-1.html) 版本升级成功后需要注意的问题版本兼容性是版本升级最重要的问题,当从低版本升级到高版本,高版本肯定有一些特性是低版本没有的,在低版本刚升级到高版本后,一定先让我们的业务程序运行一段时间,只有在线上正常运行一段时间后,我们才可以开始使用非兼容的新特性。我们在目标数据库上执行db.adminCommand( { setFeatureCompatibilityVersion:"3.4" } ),执行完这个命令后才表示打开3.4数据库版本的非兼容特性,你的应用程序才能开始使用3.4的非兼容新特性。 版本降级如果升级到高版本一段时间后,因为各种原因想继续使用以前的老版本,那就需要进行版本降级处理。版本降级中最复杂的问题还是兼容特性的处理,如果你已经使用了高版本的一些新特性,而这些特性在低版本中是不支持的,那么将版本降级到低版本mongodb肯定会运行出错。那么在替换 老版本的二进制程序前,我们首先需要移除高版本里面的非兼容特性,官网上有移除高版本非兼容特性的指导步骤,执行这些步骤就可以把非兼容的特性去掉,原理就是这些非兼容特性在生成的时候其实都在每个记录里面增加一个特殊的字段用于标明是新特性,查找含有这些标记的记录然后将其进行降级处理。昨晚非兼容特性降级处理后就可以执行二进制降级了,将高版本的二进制降级成低版本的二进制,步骤可以参考官网文档.13503
  • [技术干货] mongodb 查询命令及参数详解(1)
    本帖最后由 Nosql_newbee 于 2018-4-2 08:53 编辑 本文将详细介绍mongodb查询相关命令,参数,主要包括以下几个方面: 用find或者findone函数查询; $条件查询; 特定类型的查询。 首先**测试数据 db.user.insert([{"username":"test01","email":"test@01","age":10},{"username":"test02","email":"test@02","age":20},{"username":"test03","email":"test@03","age":30},{"username":"test04","email":"test@04","age":40}]) 使用find进行查询,返回一个集合中文档的子集,子集的范围从0个文档到整个集合; db.user.find(query, projection) 第一个参数是查询条件(可选),第二个参数是定义哪些信息需要返回(可选)。当参数为空时指查询集合中的所有文档: db.user.find() 查询简单的类型,只要指定想要查询的值就可以了,例如要查询collection 集合中username 为test的所有文档: db.user.find({"username":"test01"}) 有时并不需要将文档中的所有值返回,指定其中某些字段进行返回,例如要查询collection集合中用户的email: db.user.find({},{"email":1}) email的值为boolen类型,true为只返回该字段,fasle为返回除该字段的其他值,"_id"默认被返回,如果不想返回"_id" db.user.find({},{"_id":0}) 查询条件: "$lt","$lte","$gt","$gte"就是全部的比较操作符,分别对应.=,>,>=。例如查询age大于20的文档 db.user.find({"age":{"$gt":20}}), 支持多个条件与, db.user.find({"age":{"$gt":20,"$lt":40}}) 或查询: mongodb支持两种or查询方式:"$in"可以用来查询一个键的多个值,"$or"更通用些。 如果你个键需要与多个值进行匹配的话,就要用$in操作符,例如查找age为20,30,40的所有文档 db.user.find({"age":{"$in":[20,30,40]}}) $in 的匹配值中可以指定不同的类型,$nin 返回与数组中所有条件都不匹配的文档,例如,查找username为非test01的文档 db.user.find({"username":{"$nin":["test01"]}}) $in只能对单键尽心查询,要查询username为test01 或者age为30的文档,就需要用$or $or接受一个包含所有可能条件的数组作为参数,例如上面的例子可以写成: db.user.find({"$or":[{"username":"test01"},{"age":30}]}) $not $not是元条件句,即可以用在任何其他条件之上,用$not可以实现$nin的效果 db.user.find({"age":{$not:{$in:[20,30]}}}) 特定类型的查询: NULL: null类型有点奇怪,他确实可以与自身匹配,所以要是有个包含null的文档集合,通过查询语句可以查到。但是,null还会匹配不包含这个键的文档,例如查询没有address键值的文档 db.user.find({"adress":null}) 如果仅想匹配键值为null的文档,既要检查该键的值是否存在还要通过$exist条件判断该键值已存在 db.user.find({"address":{"$in":[null],"$exist":true}}) 这里对null的匹配并没有类似$eq的语句,使用$in效果一样的 正则表达式: 正则表达式可以灵活的匹配字符串,例如,要想查找username为test开头的文档 db.user.find({"username":/test/i}) MongDB使用Perl兼容的正则表达式(PCRE)库来匹配正则表达式,任何PCRE支持的正则表达式语法都能被mongoDB接受,建议在查询使用正则表达式前,先在JavaScript shell中检查下语法,确保结果是你想要的。
  • [技术干货] 使用Mongodb聚合操作
    聚合操作用来处理数据记录,然后返回计算过的结果。聚合操作针对一组数据也就是多个文档进行处理,可以对这组数据进行多种操作的运算,然后得到具体的结果。 Mongodb提供了3种方式的聚合功能: [*]聚合管道 [*]map-reduce [*]简单的聚合方法 聚合管道 Mongodb的聚合框架是一种数据处理管道的模型,每个文档通过由多个阶段组成的通道进行处理转化,然后得到聚合的结果。基本的管道操作就是一些过滤操作,比如查询,或者转化文档输出的格式。 $match 筛选条件,过滤掉不满足条件的文档,可以使用常规的查询操作符,如gt、lt、$in等 eg: db.orders.aggregate( {"$match": {"status":"A"}} ) $project 投射 1. 用于包含、排除字段: 设置要查询或者要过滤掉的字段,0: 要过滤掉的字段,不显示,1:需要查询的字段 2. 对字段重命名, 3. 在投射中使用一些【表达式】:数学表达式、日期表达式、字符串表达式、逻辑表达式(比较表达式、布尔表达式、控制语句) eg:db.orders.aggregate( {"$match": {"status": "A"} }, {"$project": { "cust_id": 0, "amount":1, "state": "$status", "amounts":{"$add": ["$amount", "$amount ", 100]}}} ) // $project: 当字段的值是0或者1时用于过滤字段,当键是一个自定义的字符串,值为$跟上原来的字段,表示要对该字段进行重命名 // 算数表达式:用于对一组数字 加减乘除取余$add: [exp1, exp2, ... expN]: 对数组中的多个元素进行相加, 示例是对amount字段的值 + amount字段的值 + 100 作为amounts字段的值 其他的管道操作还有一些分组,排序 以及聚合数组内容的功能。比如计算和或连接字符串。 $group: 分组 使用_id指定要分组的键,要分组的键也可以是多个,使用其他自定义的字段用于统计 _id:用于指定要分组的键 total是自定义字段,要统计的结果 13495 $sort: 用于对上一次处理的结果进行排序,1:升序 -1:降序 eg:db.orders.aggregate({ "$match": {"status": "A"}, "$sort ": {"amount": "-1"}} ) //将筛选后的结果按照amount降序排列 $limit:用于条数限制 $skip:跳过前N条文档,和limit结合可用于分页 eg:db.orders.aggregate({ "$match": {"status":"A"}, "$ limit ":10}, "$ skip ":5} ) 聚合管道使用mongodb原生命令提供了有效的数据聚合能力,是Mongodb聚合操作的首选。聚合操作可用于分片集合中。聚合操作也可以通过索引来提高性能。另外聚合管道也具有内部优化过程。 map-reduce map-reduce有两个过程,map阶段将每一个文档映射到一个或多个对象上,reduce阶段然后组合map操作的输出。一般map-reduce还有一个finalize操作,可以将处理的结果进行修改。map-reduce 可以定义查询条件去筛选输入的文档并且对输出的结果排序和限制。map-reduce使用自定义的java-script 脚本来执行map ,reduce 操作。以及可选的finalize 操作。与聚合管道相比, 定制化的java-script脚本更加灵活。但总的来说, map-reduce相比于聚合管道,效率低而且更复杂。如下示例: 13496 简单的聚合方法 count(): 求数量 eg:db.orders.count({"status": "A"}) distinct(“filedname”): 求某个字段不同的值eg: db.orders.distinct("cust_id ")13497 group(): 用于分组计算 / key: 用于指定要分组的键 // initial: 对于分组统计的字段设置键名和初始值 // reduce: 循环每个分组中的每个文档,一组循环完了会继续下一组, eg:db.articles.group({ "key": "cust_id", "initial": {"total": 0}, "reduce": function(doc, prev) { prev. total += doc.amount; } } 参考文档:[aggregation](https://docs.mongodb.com/v3.6/aggregation)
  • [技术干货] 【MongoDB】数据库状态查询之serverStatus命令详解
    本帖最后由 Mongo_奇 于 2018-4-1 22:14 编辑MongoDB数据库的状态查询有很多种方式可供选择(比如通过数据库状态查询命令,mongostat工具和MongoDB厂商的监控服务MongoDB Monitoring Service等),本文要介绍的是一个非常实用的状态查询命令:serverStatus。 关于serverStatus: 官方文档的说明为:The serverStatus command returns a document that provides an overview of the database’s state. Monitoring applications can run this command at a regular interval to collect statistics about the instance. 即serverStatus命令会返回一个数据库状态概览信息的稳定,监控数据库的应用程序可以通过定时运行该命令来收集数据库实例的统计信息。 serverStatus命令的使用: 举例:db.runCommand({serverStatus: 1}),当然也可以使用经过mongo shell封装的命令:db.serverStatus()。如果想要输出数据库连接数和锁的信息可以这样操作:db.runCommand({serverStatus: 1, connections: 1, locks: 1}) serverStatus命令的输出:常用字段及含义:Instance Information:"host" : , 主机名 "advisoryHostFQDNs" : , 合格的域名 "version" : , MongoDB版本号 "process" : "mongod"|"mongos">, 数据库进程的类型 "pid" : , 数据库进程的进程号 "uptime" : , 数据库进程存活的秒数 "uptimeMillis" : , 数据库进程存活的毫秒数 "uptimeEstimate" : , 数据库内部粗粒度计算进程正常的运行时间 "localTime" : ISODate(""), 当前的UTC时间戳 connections:"current" : , 当前的连接数 "available" : , 可用的连接数 "totalCreated" : NumberLong() 服务启动以来创建的所有连接数 globalLock"globalLock" : { "totalTime" : , 数据库上次启动并创建全局锁的时间 "currentQueue" : "total" : , 当前等待锁的操作个数 "readers" : , 当前等待写锁的操作个数 "writers" : 当前等待读锁的操作个数 }, "activeClients" : { "total" : , 当前活跃的客户端个数 "readers" : , 当前允许读操作的活跃的客户端个数 "writers" : 当前允许写操作活跃的客户端个数 }}, network:"network" : { "bytesIn" : , 服务端接收的字节数 "bytesOut" : , 服务端发送的字节数 "numRequests" : 接收的总的请求数}, opcounters:"opcounters" : { "insert" : , 写的操作数 "query" : , 查询的操作数 "update" : , 更新的操作数 "delete" : , 删除的操作数 "getmore" : , 从游标中取数据数 "command" : 命令的操作数}, 因为serverStatus返回的字段很多,以上仅仅列举的一些关键字段,后续会做补充。同时后面还会介绍其它两个关键的查询命令:rs.status(),sh.status().
总条数:168 到第
上滑加载中