mongodb_mongodbvue - CSDN
mongodb 订阅
MongoDB是一个基于分布式文件存储 [1]  的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。 展开全文
MongoDB是一个基于分布式文件存储 [1]  的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
信息
特    点
高性能,易部署,易使用
编写语言
由C++语言编写
产品类型
基于分布式文件存储的数据库
外文名
MongoDB
mongodb特点
它的特点是高性能、易部署、易使用,存储数据非常方便。主要功能特性有:*面向集合存储,易存储对象类型的数据。 *模式自由。*支持动态查询。*支持完全索引,包含内部对象。*支持查询。*支持复制和故障恢复。*使用高效的二进制数据存储,包括大型对象(如视频等)。*自动处理碎片,以支持云计算层次的扩展性。*支持 Golang,RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。*文件存储格式为BSON(一种JSON的扩展)。*可通过网络访问。
收起全文
精华内容
参与话题
  • Mongodb 数据库

    千次阅读 多人点赞 2019-07-24 16:47:57
    mongodb 首先关系型数据库和非关系型数据库的介绍; 对于关系型的数据库,存储数据之前,必须先建表建库,随着数据的复杂度越来越高,所建表的数量也就越来越多 但是非关系型数据库却不需要如此复杂; 关系型数据库...

    后续技术类文档更新到微信公众号-------->>喜欢的扫码关注

    在这里插入图片描述

    mongodb

    首先关系型数据库和非关系型数据库的介绍;
    对于关系型的数据库,存储数据之前,必须先建表建库,随着数据的复杂度越来越高,所建表的数量也就越来越多
    但是非关系型数据库却不需要如此复杂;

    关系型数据库很强大,但是它并不能很好的应付所有的应用场景;
    MySQL的扩展性差;大数据下IO压力大;表结构更改困难。

    mongodb 易扩展,大数据量高性能,灵活的数据模型,高可用。

    mongodb有那些优势;
    1. 易扩展性;nosql数据库的种类繁多;共同的特点就是去掉了关系型数据库的关系型特性;数据之间没有关系
      这样就非常容易扩展。
    2. 大数据。高性能;nosql都具有非常高的读写性能,尤其在大数据量下,同样表现优秀,得益于它的无关系
      性,数据库结构简单;
    3. 灵活的数据模型,不需要为事先存储的数据建立字段,随时可以存储自定义格式的数据,在关系型数据库中
      增删是一件很麻烦的事,如果是一个非常大的数据量的表,增加字段简直就是噩梦。
    mongodb的数据库命令:

    查看当前数据库: db
    查看所有的数据库: show dbs 或者 show databases
    切换数据库: use db_name
    删除当前数据库:db.dropDatabase()

    mongodb的集合命令:

    1, 如果不手动创建集合;向不存在的集合中第一次加入数据的时候,集合会被自动创建出来。

    手动创建集合的命令:
    db.createCollection(name,options)
    db.createCollection(“stu”)
    db.createCollection(“sub”, { capped : true, size : 10 } )
    参数capped: 默认值为false表示不设置上限,值为true表示设置上限
    参数size: 当capped值为true时, 需要指定此参数, 表示上限⼤⼩,当⽂档达到上限时, 会将之前的数据覆盖, 单位为字节
    查看集合:show collections
    删除集合:db.集合名称.drop()

    mongodb常见的数据类型:
    Object ID: ⽂档ID
    String: 字符串, 最常⽤, 必须是有效的UTF-8
    Boolean: 存储⼀个布尔值, true或false
    Integer: 整数可以是32位或64位, 这取决于服务器
    Double: 存储浮点值
    Arrays: 数组或列表, 多个值存储到⼀个键
    Object: ⽤于嵌⼊式的⽂档, 即⼀个值为⼀个⽂档
    Null: 存储Null值
    Timestamp: 时间戳, 表示从1970-1-1到现在的总秒数
    Date: 存储当前⽇期或时间的UNIX时间格式

    字符串;
    布尔值;
    整数;
    浮点数;
    数组,列表;
    文档;
    Null;
    时间戳;
    日期;
    九种数据类型 。

    mongodb的数据插入:
    db.集合名称.insert(document)
    db.stu.insert({name:‘gj’,gender:1})
    db.stu.insert({_id:“20170101”,name:‘gj’,gender:1})

    插入文档时候如果不指定id,会自动分配;

    4.2 mongodb的保存
    命令:db.集合名称.save(document) 如果⽂档的_id已经存在则修改, 如果⽂档的_id不存在则添加

    4.3 mongodb的简单查询
    命令:db.集合名称.find()

    4.4 mongodb的更新
    命令:db.集合名称.update( ,,{multi: })

    参数query:查询条件
    参数update:更新操作符
    参数multi:可选, 默认是false,表示只更新找到的第⼀条记录, 值为true表示把满⾜条件的⽂档全部更新
    db.stu.update({name:‘hr’},{name:‘mnc’}) 更新一条
    db.stu.update({name:‘hr’},{KaTeX parse error: Expected 'EOF', got '}' at position 17: …et:{name:'hys'}}̲) 更新一条 db.st…set:{gender:0}},{multi:true}) 更新全部
    注意:“multi update only works with $ operators”

    4.5 mongodb的删除
    命令:db.集合名称.remove(,{justOne: })

    参数query:可选,删除的⽂档的条件
    参数justOne:可选, 如果设为true或1, 则只删除⼀条, 默认false, 表示删除多条
    5. mongodb的高级查询
    知识点:

    掌握mongodb的数据查询操作
    掌握比较运算符的使用
    掌握逻辑运算符的使用
    掌握范围运算符的使用
    了解正则的使用
    掌握skip和limit的使用
    掌握投影方法的使用
    掌握排序方法的使用
    了解去重方法的使用

    5.1 数据查询
    ⽅法find(): 查询

    db.集合名称.find({条件⽂档})

    ⽅法findOne():查询,只返回第⼀个

    db.集合名称.findOne({条件⽂档})

    ⽅法pretty(): 将结果格式化

    db.集合名称.find({条件⽂档}).pretty()

    5.2 比较运算符
    可以使用以下数据进行练习

    {“name” : “郭靖”, “hometown” : “蒙古”, “age” : 20, “gender” : true }
    {“name” : “⻩蓉”, “hometown” : “桃花岛”, “age” : 18, “gender” : false }
    {“name” : “华筝”, “hometown” : “蒙古”, “age” : 18, “gender” : false }
    {“name” : “⻩药师”, “hometown” : “桃花岛”, “age” : 40, “gender” : true }
    {“name” : “段誉”, “hometown” : “⼤理”, “age” : 16, “gender” : true }
    {“name” : “段王爷”, “hometown” : “⼤理”, “age” : 45, “gender” : true }
    {“name” : “洪七公”, “hometown” : “华⼭”, “age” : 18, “gender” : true }
    等于: 默认是等于判断, 没有运算符
    ⼩于:ltlessthanlt (less than) ⼩于等于:lte (less than equal)
    ⼤于:gtgreaterthangt (greater than) ⼤于等于:gte
    不等于:$ne

    例如:

    查询年龄大于18的所有学生
    db.stu.find({age:{$gte:18}})
    5.3 逻辑运算符
    逻辑运算符主要指与、或逻辑

    and:在json中写多个条件即可

    查询年龄⼤于或等于18, 并且性别为true的学⽣
    db.stu.find({age:{KaTeX parse error: Expected 'EOF', got '}' at position 7: gte:18}̲,gender:true}) …or, 值为数组, 数组中每个元素为json

    查询年龄⼤于18, 或性别为false的学⽣
    db.stu.find({KaTeX parse error: Expected '}', got 'EOF' at end of input: or:[{age:{gt:18}},{gender:false}]})

    查询年龄⼤于18或性别为男⽣, 并且姓名是郭靖
    db.stu.find({KaTeX parse error: Expected '}', got 'EOF' at end of input: or:[{age:{gte:18}},{gender:true}],name:‘gj’})
    5.4 范围运算符
    使⽤$in, $nin 判断数据是否在某个数组内

    查询年龄为18、 28的学⽣
    db.stu.find({age:{KaTeX parse error: Expected 'EOF', got '}' at position 14: in:[18,28,38]}̲}) 5.5 ⽀持正则表达式 …regex编写正则表达式

    查询sku以abc开头的数据
    db.products.find({sku:/^abc/})

    查询sku以789结尾的数据
    db.products.find({sku:{regex:789regex:'789’}})
    { “_id” : 100, “sku” : “abc123”, “description” : “Single line description.” }
    { “_id” : 101, “sku” : “abc789”, “description” : “First line\nSecond line” }
    { “_id” : 102, “sku” : “xyz456”, “description” : “Many spaces before line” }
    { “_id” : 103, “sku” : “xyz789”, “description” : “Multiple\nline description” }
    5.6 skip和limit
    ⽅法limit(): ⽤于读取指定数量的⽂档

    db.集合名称.find().limit(NUMBER)
    查询2条学⽣信息
    db.stu.find().limit(2)
    ⽅法skip(): ⽤于跳过指定数量的⽂档

    db.集合名称.find().skip(NUMBER)
    db.stu.find().skip(2)
    同时使用

    db.stu.find().limit(4).skip(5)

    db.stu.find().skip(5).limit(4)
    注意:先使用skip在使用limit的效率要高于前者

    5.7 自定义查询*
    由于mongo的shell是一个js的执行环境 使⽤$where后⾯写⼀个函数, 返回满⾜条件的数据

    查询年龄⼤于30的学⽣
    db.stu.find({
    $where:function() {
    return this.age>30;}
    })
    5.8 投影
    在查询到的返回结果中, 只选择必要的字段

    命令:db.集合名称.find({},{字段名称:1,…})

    参数为字段与值, 值为1表示显示, 值为0不显 特别注意: 对于_id列默认是显示的, 如果不显示需要明确设置为0

    db.stu.find({},{_id:0,name:1,gender:1})

    5.9 排序
    ⽅法sort(), ⽤于对 集进⾏排序

    命令:db.集合名称.find().sort({字段:1,…})

    参数1为升序排列 参数-1为降序排列

    根据性别降序, 再根据年龄升序
    db.stu.find().sort({gender:-1,age:1})
    5.10 统计个数
    ⽅法count()⽤于统计结果集中⽂档条数

    命令:db.集合名称.find({条件}).count() 命令:db.集合名称.count({条件})

    db.stu.find({gender:true}).count()
    db.stu.count({age:{$gt:20},gender:true})
    5.11 消除重复
    ⽅法distinct()对数据进⾏去重

    命令:db.集合名称.distinct(‘去重字段’,{条件})

    db.stu.distinct(‘hometown’,{age:{$gt:18}})

    1. mongodb的常用管道和表达式
      知识点:

    掌握mongodb中管道的语法
    掌握mongodb中管道命令
    2.1 常用管道命令
    在mongodb中,⽂档处理完毕后, 通过管道进⾏下⼀次处理 常用管道命令如下:

    $group: 将集合中的⽂档分组, 可⽤于统计结果
    $match: 过滤数据, 只输出符合条件的⽂档
    $project: 修改输⼊⽂档的结构, 如重命名、 增加、 删除字段、 创建计算结果
    $sort: 将输⼊⽂档排序后输出
    $limit: 限制聚合管道返回的⽂档数
    skip2.2:skip: 跳过指定数量的⽂档, 并返回余下的⽂档 2.2 常用表达式 表达式:处理输⼊⽂档并输出 语法:表达式:'列名’ 常⽤表达式:

    $sum: 计算总和, $sum:1 表示以⼀倍计数
    $avg: 计算平均值
    $min: 获取最⼩值
    $max: 获取最⼤值
    $push: 在结果⽂档中插⼊值到⼀个数组中

    mongodb创建索引;

    加快查询速度;
    进行数据的去重;

    mongodb创建简单的索引方法
    语法:

    db.集合.ensureIndex({属性:1}),1表示升序, -1表示降序
    db.集合.createIndex({属性:1})
    上面两个命令效果等价
    具体操作:db.db_name.ensureIndex({name:1})

    添加唯一索引的语法:

    db.collection_name.ensureIndex({“name”:1},{“unique”:true})

    删除索引
    语法:db.t1.dropIndex({‘索引名称’:1})

    建立复合索引

    在进行数据去重的时候,可能用一个字段来保证数据的唯一性,这个时候可以考虑建立复合索引来实现。

    例如:抓全贴吧信息,如果把帖子的名字作为唯一索引对数据进行去重是不可取的,因为可能有很多帖子名字相同

    建立复合索引的语法:db.collection_name.ensureIndex({字段1:1,字段2:1})

    python与 mongodb交互:

    from pymongo import MongoClient
    client = MongoClient(host,port)
    collection = client[db名][集合名]
    添加一条数据

    ret = collection.insert_one({“name”:“test10010”,“age”:33})
    print(ret)
    添加多条数据

    item_list = [{“name”:“test1000{}”.format(i)} for i in range(10)]
    insert_many接收一个列表,列表中为所有需要插入的字典
    t = collection.insert_many(item_list)

    查找一条数据

    find_one查找并且返回一个结果,接收一个字典形式的条件
    t = collection.find_one({“name”:“test10005”})
    print(t)
    查找全部数据

    结果是一个Cursor游标对象,是一个可迭代对象,可以类似读文件的指针,但是只能够进行一次读取

    find返回所有满足条件的结果,如果条件为空,则返回数据库的所有
    t = collection.find({“name”:“test10005”})
    #结果是一个Cursor游标对象,是一个可迭代对象,可以类似读文件的指针,
    for i in t:
    print(i)
    for i in t: #此时t中没有内容
    print(i)
    更新一条数据 注意使用$set命令

    update_one更新一条数据
    collection.update_one({“name”:“test10005”},{"$set":{“name”:“new_test10005”}})
    更行全部数据

    update_one更新全部数据
    collection.update_many({“name”:“test10005”},{"$set":{“name”:“new_test10005”}})
    删除一条数据

    delete_one删除一条数据
    collection.delete_one({“name”:“test10010”})
    删除全部数据

    delete_may删除所有满足条件的数据
    collection.delete_many({“name”:“test10010”})

    展开全文
  • MongoDB数据库从入门到精通

    千人学习 2019-12-18 15:11:50
    本课程是MongoDB数据库的精讲课程,课程从环境搭建开始详细讲述了MongoDB的各个方面,内容涵盖:Mongo shell、数据库CRUD、聚合、索引、数据库模型、MongoDB Java开发和MongoDB Python开发。
  • MongoDB的简单认识及基本操作

    千次阅读 多人点赞 2019-01-18 19:14:59
    MongoDB 一. 简介 MongoDB是一款强大、灵活、且易于扩展的通用型数据库。 1、易用性 MongoDB是一个面向文档(document-oriented)的数据库,而不是关系型数据库。 不采用关系型主要是为了获得更好得扩展性。当然还有...

    MongoDB

    一. 简介

    MongoDB是一款强大、灵活、且易于扩展的通用型数据库。

    1、易用性

    MongoDB是一个面向文档(document-oriented)的数据库,而不是关系型数据库。
    不采用关系型主要是为了获得更好得扩展性。当然还有一些其他好处,与关系数据库相比,面向文档的数据库不再有“行“(row)的概念取而代之的是更为灵活的“文档”(document)模型。
    通过在文档中嵌入文档和数组,面向文档的方法能够仅使用一条记录来表现复杂的层级关系,这与现代的面向对象语言的开发者对数据的看法一致。
    另外,不再有预定义模式(predefined schema):文档的键(key)和值(value)不再是固定的类型和大小。由于没有固定的模式,根据需要添加或删除字段变得更容易了。通常由于开发者能够进行快速迭代,所以开发进程得以加快。而且,实验更容易进行。开发者能尝试大量的数据模型,从中选一个最好的。
    

    2、易扩展性

    应用程序数据集的大小正在以不可思议的速度增长。随着可用带宽的增长和存储器价格的下降,即使是一个小规模的应用程序,需要存储的数据量也可能大的惊人,甚至超出
    了很多数据库的处理能力。过去非常罕见的T级数据,现在已经是司空见惯了。
    由于需要存储的数据量不断增长,开发者面临一个问题:应该如何扩展数据库,分为纵向扩展和横向扩展,纵向扩展是最省力的做法,但缺点是大型机一般都非常贵,而且
    当数据量达到机器的物理极限时,花再多的钱也买不到更强的机器了,此时选择横向扩展更为合适,但横向扩展带来的另外一个问题就是需要管理的机器太多。
    MongoDB的设计采用横向扩展。面向文档的数据模型使它能很容易地在多台服务器之间进行数据分割。MongoDB能够自动处理跨集群的数据和负载,自动重新分配文档,以及将
    用户的请求路由到正确的机器上。这样,开发者能够集中精力编写应用程序,而不需要考虑如何扩展的问题。如果一个集群需要更大的容量,只需要向集群添加新服务器,MongoDB就会自动将现有的数据向新服务器传送
    

    3、丰富的功能

    MongoDB作为一款通用型数据库,除了能够创建、读取、更新和删除数据之外,还提供了一系列不断扩展的独特功能
    #1、索引
    支持通用二级索引,允许多种快速查询,且提供唯一索引、复合索引、地理空间索引、全文索引
    
    #2、聚合
    支持聚合管道,用户能通过简单的片段创建复杂的集合,并通过数据库自动优化
    
    #3、特殊的集合类型
    支持存在时间有限的集合,适用于那些将在某个时刻过期的数据,如会话session。类似地,MongoDB也支持固定大小的集合,用于保存近期数据,如日志
    
    #4、文件存储
    支持一种非常易用的协议,用于存储大文件和文件元数据。MongoDB并不具备一些在关系型数据库中很普遍的功能,如链接join和复杂的多行事务。省略
    这些的功能是处于架构上的考虑,或者说为了得到更好的扩展性,因为在分布式系统中这两个功能难以高效地实现
    

    4、卓越的性能

    MongoDB的一个主要目标是提供卓越的性能,这很大程度上决定了MongoDB的设计。MongoDB把尽可能多的内存用作缓存cache,视图为每次查询自动选择正确的索引。
    总之各方面的设计都旨在保持它的高性能
    虽然MongoDB非常强大并试图保留关系型数据库的很多特性,但它并不追求具备关系型数据库的所有功能。只要有可能,数据库服务器就会将处理逻辑交给客户端。这种精简方式的设计是MongoDB能够实现如此高性能的原因之一
    

    二. MangoDB基础知识

    在这里插入图片描述

    1、文档是MongoDB的核心概念。文档就是键值对的一个有序集{‘msg’:‘hello’,‘foo’:3}。类似于python中的有序字典。

    需要注意的是:
    #1、文档中的键/值对是有序的。
    #2、文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
    #3、MongoDB区分类型和大小写。
    #4、MongoDB的文档不能有重复的键。
    #5、文档中的值可以是多种不同的数据类型,也可以是一个完整的内嵌文档。文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。
    
    文档键命名规范:
    #1、键不能含有\0 (空字符)。这个字符用来表示键的结尾。
    #2、.和$有特别的意义,只有在特定环境下才能使用。
    #3、以下划线"_"开头的键是保留的(不是严格要求的)。
    

    2、集合就是一组文档。如果将MongoDB中的一个文档比喻为关系型数据的一行,那么一个集合就是相当于一张表

    #1、集合存在于数据库中,通常情况下为了方便管理,不同格式和类型的数据应该插入到不同的集合,但其实集合没有固定的结构,这意味着我们完全可以把不同格式和类型的数据统统插入一个集合中。
    
    #2、组织子集合的方式就是使用“.”,分隔不同命名空间的子集合。
    比如一个具有博客功能的应用可能包含两个集合,分别是blog.posts和blog.authors,这是为了使组织结构更清晰,这里的blog集合(这个集合甚至不需要存在)跟它的两个子集合没有任何关系。
    在MongoDB中,使用子集合来组织数据非常高效,值得推荐
    
    #3、当第一个文档插入时,集合就会被创建。合法的集合名:
    集合名不能是空字符串""。
    集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。
    集合名不能以"system."开头,这是为系统集合保留的前缀。
    用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。
    

    3、数据库:在MongoDB中,多个文档组成集合,多个集合可以组成数据库

    数据库也通过名字来标识。数据库名可以是满足以下条件的任意UTF-8字符串:
    #1、不能是空字符串("")。
    #2、不得含有' '(空格)、.、$、/、\和\0 (空字符)。
    #3、应全部小写。
    #4、最多64字节。
    
    有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。
    #1、admin: 从身份认证的角度讲,这是“root”数据库,如果将一个用户添加到admin数据库,这个用户将自动获得所有数据库的权限。再者,一些特定的服务器端命令也只能从admin数据库运行,如列出所有数据库或关闭服务器
    #2、local: 这个数据库永远都不可以复制,且一台服务器上的所有本地集合都可以存储在这个数据库中
    #3、config: MongoDB用于分片设置时,分片信息会存储在config数据库中
    

    4、强调:把数据库名添加到集合名前,得到集合的完全限定名,即命名空间

    例如:
    如果要使用cms数据库中的blog.posts集合,这个集合的命名空间就是
    cmd.blog.posts。命名空间的长度不得超过121个字节,且在实际使用中应该小于100个字节
    

    三. 安装

    1.安装

    #1、安装路径为D:\MongoDB,将D:\MongoDB\bin目录加入环境变量
    
    #2、新建目录与文件
    D:\MongoDB\data\db
    D:\MongoDB\log\mongod.log
    
    #3、新建配置文件mongod.cfg,参考:https://docs.mongodb.com/manual/reference/configuration-options/
    systemLog:
       destination: file
       path: "D:\MongoDB\log\mongod.log"
       logAppend: true
    storage:
       journal:
          enabled: true
       dbPath: "D:\MongoDB\data\db"
    net:
       bindIp: 0.0.0.0
       port: 27017
    setParameter:
       enableLocalhostAuthBypass: false
        
    #4、制作系统服务
    mongod --config "D:\MongoDB\mongod.cfg" --bind_ip 0.0.0.0 --install
    或者直接在命令行指定配置
    mongod --bind_ip 0.0.0.0 --port 27017 --logpath D:\MongoDB\log\mongod.log --logappend --dbpath D:\MongoDB\data\db  --serviceName "MongoDB" --serviceDisplayName "MongoDB"  --install
    
            
    先停掉服务:net stop MongoDB
    然后移除服务:mongo --remove
    再重新制作服务,需要加上--auth,表示加载认证功能
    mongod --bind_ip 0.0.0.0 --port 27017 --logpath D:\MongoDB\log\mongod.log --logappend --dbpath D:\MongoDB\data\db  --serviceName "MongoDB" --serviceDisplayName "MongoDB"  --install --auth       
            
    
    
    #5、启动\关闭
    net start MongoDB
    net stop MongoDB
    
    #6、登录
    mongo
    
    链接:http://www.runoob.com/mongodb/mongodb-window-install.html
    

    2. 账号管理

    
    #1、创建账号
    use admin
    db.createUser(
      {
        user: "root",
        pwd: "123",
        roles: [ { role: "root", db: "admin" } ]
      }
    )
    
    use test
    db.createUser(
      {
        user: "tom",
        pwd: "123",
        roles: [ { role: "readWrite", db: "test" },
                 { role: "read", db: "db1" } ]
      }
    )
    
    
    #2、重启数据库
    mongod --remove
    mongod --config "C:\mongodb\mongod.cfg" --bind_ip 0.0.0.0 --install --auth
    
    #3、登录:注意使用双引号而非单引号
    mongo --port 27017 -u "root" -p "123" --authenticationDatabase "admin"
    
    也可以在登录之后用db.auth("账号","密码")登录
    mongo
    use admin
    db.auth("root","123")
    
    #推荐博客:https://www.cnblogs.com/zhoujinyi/p/4610050.html
    

    3. 命令行shell

    #1、mongo 127.0.0.1:27017/config #连接到任何数据库config
    
    #2、mongo --nodb #不连接到任何数据库
    
    #3、启动之后,在需要时运行new Mongo(hostname)命令就可以连接到想要的mongod了:
    > conn=new Mongo('127.0.0.1:27017')
    connection to 127.0.0.1:27017
    > db=conn.getDB('admin')
    admin
    
    #4、help查看帮助
    
    #5、mongo时一个简化的JavaScript shell,是可以执行JavaScript脚本的
    

    4."_id"与ObjectId

    MongoDB中存储的文档必须有一个"_id"键。这个键的值可以是任意类型,默认是个ObjectId对象。
    在一个集合里,每个文档都有唯一的“_id”,确保集合里每个文档都能被唯一标识。
    不同集合"_id"的值可以重复,但同一集合内"_id"的值必须唯一
    
    #1、ObjectId
    ObjectId是"_id"的默认类型。因为设计MongoDb的初衷就是用作分布式数据库,所以能够在分片环境中生成
    唯一的标识符非常重要,而常规的做法:在多个服务器上同步自动增加主键既费时又费力,这就是MongoDB采用
    ObjectId的原因。
    ObjectId采用12字节的存储空间,是一个由24个十六进制数字组成的字符串
        0|1|2|3|   4|5|6|     7|8    9|10|11    
        时间戳      机器      PID    计数器
    如果快速创建多个ObjectId,会发现每次只有最后几位有变化。另外,中间的几位数字也会变化(要是在创建过程中停顿几秒)。
    这是ObjectId的创建方式导致的,如上图
    
    时间戳单位为秒,与随后5个字节组合起来,提供了秒级的唯一性。这个4个字节隐藏了文档的创建时间,绝大多数驱动程序都会提供
    一个方法,用于从ObjectId中获取这些信息。
    
    因为使用的是当前时间,很多用户担心要对服务器进行时钟同步。其实没必要,因为时间戳的实际值并不重要,只要它总是不停增加就好。
    接下来3个字节是所在主机的唯一标识符。通常是机器主机名的散列值。这样就可以保证不同主机生成不同的ObjectId,不产生冲突
    
    接下来连个字节确保了在同一台机器上并发的多个进程产生的ObjectId是唯一的
    
    前9个字节确保了同一秒钟不同机器不同进程产生的ObjectId是唯一的。最后3个字节是一个自动增加的 计数器。确保相同进程的同一秒产生的
    ObjectId也是不一样的。
    
    #2、自动生成_id
    如果插入文档时没有"_id"键,系统会自帮你创建 一个。可以由MongoDb服务器来做这件事。
    但通常会在客户端由驱动程序完成。这一做法非常好地体现了MongoDb的哲学:能交给客户端驱动程序来做的事情就不要交给服务器来做。
    这种理念背后的原因是:即便是像MongoDB这样扩展性非常好的数据库,扩展应用层也要比扩展数据库层容易的多。将工作交给客户端做就
    减轻了数据库扩展的负担。
    

    5.MangoDB基本数据类型

    #1、null:用于表示空或不存在的字段
    d={'x':null}
    #2、布尔型:true和false
    d={'x':true,'y':false}
    #3、数值
    d={'x':3,'y':3.1415926}
    #4、字符串
    d={'x':'tom'}
    #5、日期
    d={'x':new Date()}
    d.x.getHours()
    #6、正则表达式
    d={'pattern':/^egon.*?nb$/i}
    
    正则写在//内,后面的i代表:
    i 忽略大小写
    m 多行匹配模式
    x 忽略非转义的空白字符
    s 单行匹配模式
    
    #7、数组
    d={'x':[1,'a','v']}
    
    #8、内嵌文档
    user={'name':'tom','addr':{'country':'China','city':'YT'}}
    user.addr.country
    
    #9、对象id:是一个12字节的ID,是文档的唯一标识,不可变
    d={'x':ObjectId()}
    

    四. CRUD操作

    1、数据库操作

    #1、增
    use db1 #如果数据库不存在,则创建数据库,否则切换到指定数据库。
    
    #2、查
    show dbs #查看所有
    可以看到,我们刚创建的数据库db1并不在数据库的列表中, 要显示它,我们需要向db1数据库插入一些数据。
    db.table1.insert({'a':1})
    
    #3、删
    use db1 #先切换到要删的库下
    db.dropDatabase() #删除当前库
    

    2、集合操作

    #1、增
    当第一个文档插入时,集合就会被创建
    > use database1
    switched to db database1
    > db.table1.insert({'a':1})
    WriteResult({ "nInserted" : 1 })
    > db.table2.insert({'b':2})
    WriteResult({ "nInserted" : 1 })
    
    db.user
    db.user.info	表名是user.info,跟user表没有任何关系
    db.user.auth
    
    
    
    #2、查
    > show tables
    table1
    table2
    
    #3、删
    > db.table1.drop()
    true
    > show tables
    table2
    

    3、文档操作

    #1、没有指定_id则默认ObjectId,_id不能重复,且在插入后不可变
    
    #2、插入单条
    user0={
        "name":"tom",
        "age":10,
        'hobbies':['music','read','dancing'],
        'addr':{
            'country':'China',
            'city':'BJ'
        }
    }
    
    db.test.insert(user0)
    db.test.find()
    
    #3、插入多条
    user1={
        "_id":1,
        "name":"zhang3",
        "age":10,
        'hobbies':['music','read','dancing'],
        'addr':{
            'country':'China',
            'city':'weifang'
        }
    }
    
    user2={
        "_id":2,
        "name":"li4",
        "age":20,
        'hobbies':['music','read','run'],
        'addr':{
            'country':'China',
            'city':'hebei'
        }
    }
    
    
    user3={
        "_id":3,
        "name":"wang5",
        "age":30,
        'hobbies':['music','drink'],
        'addr':{
            'country':'China',
            'city':'heibei'
        }
    }
    
    user4={
        "_id":4,
        "name":"zhao6",
        "age":40,
        'hobbies':['music','read','dancing','tea'],
        'addr':{
            'country':'China',
            'city':'BJ'
        }
    }
    
    user5={
        "_id":5,
        "name":"sun7",
        "age":50,
        'hobbies':['music','read',],
        'addr':{
            'country':'China',
            'city':'henan'
        }
    }
    db.user.insertMany([user1,user2,user3,user4,user5])
    
    
    db.t1.insert({"_id":1,"a":"1","b":"2","c":"3"})
    db.t1.save({"_id":1,"z":"6"})   有就用新的记录覆盖掉原来的记录,无就新增
    
    • 比较运算
    # SQL:=,!=,>,<,>=,<=
    # MongoDB:{key:value}代表什么等于什么
    "$ne"====>不等于
    "$gt"====>大于
    "$lt"====>小于
    "gte"====>大于等于
    "lte"====>小于等于
    其中"$ne"能用于所有数据类型
    
    #1、select * from db1.user where name = "alex";
    db.user.find({'name':'alex'})
    
    #2、select * from db1.user where name != "alex";
    db.user.find({'name':{"$ne":'alex'}})
    
    #3、select * from db1.user where id > 2;
    db.user.find({'_id':{'$gt':2}})
    
    #4、select * from db1.user where id < 3;
    db.user.find({'_id':{'$lt':3}})
    
    #5、select * from db1.user where id >= 2;
    db.user.find({"_id":{"$gte":2,}})
    
    #6、select * from db1.user where id <= 2;
    db.user.find({"_id":{"$lte":2}})
    
    • 逻辑运算
    # SQL:and,or,not
    # MongoDB:字典中逗号分隔的多个条件是and关系,"$or"的条件放到[]内,"$not"
    
    #1、select * from db1.user where id >= 2 and id < 4;
    db.user.find({'_id':{"$gte":2,"$lt":4}})
    
    #2、select * from db1.user where id >= 2 and age < 40;
    db.user.find({"_id":{"$gte":2},"age":{"$lt":40}})
    
    #3、select * from db1.user where id >= 5 or name = "alex";
    db.user.find({
        "$or":[
            {'_id':{"$gte":5}},
            {"name":"alex"}
            ]
    })
    
    #4、select * from db1.user where id % 2=1;
    db.user.find({'_id':{"$mod":[2,1]}})
    
    #5、上题,取反
    db.user.find({'_id':{"$not":{"$mod":[2,1]}}})
    
    • 成员运算
    # SQL:in,not in
    # MongoDB:"$in","$nin"
    
    #1、select * from db1.user where age in (20,30,31);
    db.user.find({"age":{"$in":[20,30,31]}})
    
    #2、select * from db1.user where name not in ('alex','yuanhao');
    db.user.find({"name":{"$nin":['alex','yuanhao']}})
    
    • 正则匹配
    # SQL: regexp 正则
    # MongoDB: /正则表达/i
    
    #1、select * from db1.user where name regexp '^j.*?(g|n)$';
    db.user.find({'name':/^j.*?(g|n)$/i})
    
    • 去指定的字段
    #1、select name,age from db1.user where id=3;
    db.user.find({'_id':3},{'_id':0,'name':1,'age':1})
    1:代表要,类似True
    0:代表不要,类似Flase,默认是0
    
    • 查询数组
    #1、查看有dancing爱好的人
    db.user.find({'hobbies':'dancing'})
    
    #2、查看既有dancing爱好又有tea爱好的人
    db.user.find({
        'hobbies':{
            "$all":['dancing','tea']
            }
    })
    
    #3、查看第4个爱好为tea的人:".方法"
    db.user.find({"hobbies.3":'tea'})
    
    #4、查看所有人最后两个爱好:"$slice"
    db.user.find({},{'hobbies':{"$slice":-2},"age":0,"_id":0,"name":0,"addr":0})
    
    #5、查看所有人的第2个到第3个爱好
    db.user.find({},{'hobbies':{"$slice":[1,2]},"age":0,"_id":0,"name":0,"addr":0})
    
    > db.blog.find().pretty()
    {
            "_id" : 1,
            "name" : "sun7公司破产的真相",
            "comments" : [
                    {
                            "name" : "zhang3",
                            "content" : "sun7是谁???",
                            "thumb" : 200
                    },
                    {
                            "name" : "li4",
                            "content" : "我去,真的假的",
                            "thumb" : 300
                    },
                    {
                            "name" : "wang5",
                            "content" : "吃喝嫖赌抽,欠下两个亿",
                            "thumb" : 40
                    },
                    {
                            "name" : "zhao6",
                            "content" : "丐帮欢迎你",
                            "thumb" : 0
                    }
            ]
    }
    db.blog.find({},{'comments':{"$slice":-2}}).pretty() #查询最后两个
    db.blog.find({},{'comments':{"$slice":[1,2]}}).pretty() #查询1到2
    
    • 排序
    # 排序:1代表升序,-1代表降序
    db.user.find().sort({"name":1})
    db.user.find().sort({"age":-1,'_id':1})
    
    • 分页
    # 分页:limit代表取多少个document,skip代表跳过前多少个document。 
    db.user.find().sort({'age':1}).limit(1).skip(2)
    
    • 获取数量
    # 获取数量
    db.user.count({'age':{"$gt":30}}) 
    
    --或者
    db.user.find({'age':{"$gt":30}}).count()
    
    • 其他
    #1、{'key':null} 匹配key的值为null或者没有这个key
    db.t2.insert({'a':10,'b':111})
    db.t2.insert({'a':20})
    db.t2.insert({'b':null})
    
    > db.t2.find({"b":null})
    { "_id" : ObjectId("5a5cc2a7c1b4645aad959e5a"), "a" : 20 }
    { "_id" : ObjectId("5a5cc2a8c1b4645aad959e5b"), "b" : null }
    
    #2、查找所有
    db.user.find() #等同于db.user.find({})
    db.user.find().pretty()
    
    #3、查找一个,与find用法一致,只是只取匹配成功的第一个
    db.user.findOne({"_id":{"$gt":3}})
    
    #4、去重
    db.user.find().distinct()
    
    • update语法介绍
    update() 方法用于更新已存在的文档。语法格式如下:
    db.collection.update(
       <query>,
       <update>,
       {
         upsert: <boolean>,
         multi: <boolean>,
         writeConcern: <document>
       }
    )
    参数说明:对比update db1.t1 set name='zhangsan',sex='Male' where name='zhang3' and age=18;
    
    query : 相当于where条件。
    update : update的对象和一些更新的操作符(如$,$inc...等,相当于set后面的
    upsert : 可选,默认为false,代表如果不存在update的记录不更新也不插入,设置为true代表插入。
    multi : 可选,默认为false,代表只更新找到的第一条记录,设为true,代表更新找到的全部记录。
    writeConcern :可选,抛出异常的级别。
    
    更新操作是不可分割的:若两个更新同时发送,先到达服务器的先执行,然后执行另外一个,不会破坏文档。
    
    
    • 覆盖式
    #注意:除非是删除,否则_id是始终不会变的
    #1、覆盖式:
    db.user.update({'age':20},{"name":"wang5","hobbies_count":3})
    是用{"_id":2,"name":"wang5","hobbies_count":3}覆盖原来的记录
    
    #2、一种最简单的更新就是用一个新的文档完全替换匹配的文档。这适用于大规模式迁移的情况。例如
    var obj=db.user.findOne({"_id":2})
    
    obj.username=obj.name+'SB'
    obj.hobbies_count++
    delete obj.age
    
    db.user.update({"_id":2},obj)
    
    • 设置:$set
    #设置:$set
    
    通常文档只会有一部分需要更新。可以使用原子性的更新修改器,指定对文档中的某些字段进行更新。
    更新修改器是种特殊的键,用来指定复杂的更新操作,比如修改、增加后者删除
    
    #1、update db1.user set  name="wang5" where id = 2
    db.user.update({'_id':2},{"$set":{"name":"wang5",}})
    
    #2、没有匹配成功则新增一条{"upsert":true}
    db.user.update({'_id':6},{"$set":{"name":"wang5","age":18}},{"upsert":true})
    
    #3、默认只改匹配成功的第一条,{"multi":改多条}
    db.user.update({'_id':{"$gt":4}},{"$set":{"age":28}})
    db.user.update({'_id':{"$gt":4}},{"$set":{"age":38}},{"multi":true})
    
    #4、修改内嵌文档,把名字为wang5的人所在的地址国家改成Japan
    db.user.update({'name':"wang5"},{"$set":{"addr.country":"Japan"}})
    
    #5、把名字为wang5的人的地2个爱好改成piao
    db.user.update({'name':"wang5"},{"$set":{"hobbies.1":"piao"}})
    
    #6、删除wang5的爱好,$unset
    db.user.update({'name':"wang5"},{"$unset":{"hobbies":""}})
    
    • 增加和减少:$inc
    #增加和减少:$inc
    
    #1、所有人年龄增加一岁
    db.user.update({},
        {
            "$inc":{"age":1}
        },
        {
            "multi":true
        }
        )
    #2、所有人年龄减少5岁
    db.user.update({},
        {
            "$inc":{"age":-5}
        },
        {
            "multi":true
        }
        )
    
    • 添加删除数组内元素:push,push,pop,$pull
    #添加删除数组内元素
        
    往数组内添加元素:$push
    #1、为名字为wang5的人添加一个爱好read
    db.user.update({"name":"wang5"},{"$push":{"hobbies":"read"}})
    
    #2、为名字为wang5的人一次添加多个爱好tea,dancing
    db.user.update({"name":"wang5"},{"$push":{
        "hobbies":{"$each":["tea","dancing"]}
    }})
    
    按照位置且只能从开头或结尾删除元素:$pop
    #3、{"$pop":{"key":1}} 从数组末尾删除一个元素
    
    db.user.update({"name":"wang5"},{"$pop":{
        "hobbies":1}
    })
    
    #4、{"$pop":{"key":-1}} 从头部删除
    db.user.update({"name":"wang5"},{"$pop":{
        "hobbies":-1}
    })
    
    #5、按照条件删除元素,:"$pull" 把符合条件的统统删掉,而$pop只能从两端删
    db.user.update({'addr.country':"China"},{"$pull":{
        "hobbies":"read"}
    },
    {
        "multi":true
    }
    )
    
    • 避免添加重复:"$addToSet"
    #避免添加重复:"$addToSet"
    
    db.urls.insert({"_id":1,"urls":[]})
    
    db.urls.update({"_id":1},{"$addToSet":{"urls":'http://www.baidu.com'}})
    db.urls.update({"_id":1},{"$addToSet":{"urls":'http://www.baidu.com'}})
    db.urls.update({"_id":1},{"$addToSet":{"urls":'http://www.baidu.com'}})
    
    db.urls.update({"_id":1},{
        "$addToSet":{
            "urls":{
            "$each":[
                'http://www.baidu.com',
                'http://www.baidu.com',
                'http://www.xxxx.com'
                ]
                }
            }
        }
    )
    
    • 其他
    #1、了解:限制大小"$slice",只留最后n个
    
    db.user.update({"_id":5},{
        "$push":{"hobbies":{
            "$each":["read",'music','dancing'],
            "$slice":-2
        }
        }
    })
    
    #2、了解:排序The $sort element value must be either 1 or -1"
    db.user.update({"_id":5},{
        "$push":{"hobbies":{
            "$each":["read",'music','dancing'],
            "$slice":-1,
            "$sort":-1
        }
        }
    })
    
    #注意:不能只将"$slice"或者"$sort"与"$push"配合使用,且必须使用"$eah"
    
    #1、删除多个中的第一个
    db.user.deleteOne({ 'age': 8 })
    
    #2、删除国家为China的全部
    db.user.deleteMany( {'addr.country': 'China'} ) 
    
    #3、删除全部
    db.user.deleteMany({})
    
    聚合
    如果你有数据存储在MongoDB中,你想做的可能就不仅仅是将数据提取出来那么简单了;你可能希望对数据进行分析并加以利用。MongoDB提供了以下聚合工具:
    #1、聚合框架
    #2、MapReduce(详见MongoDB权威指南)
    #3、几个简单聚合命令:count、distinct和group。(详见MongoDB权威指南)
    
    #聚合框架:
    可以使用多个构件创建一个管道,上一个构件的结果传给下一个构件。
    这些构件包括(括号内为构件对应的操作符):筛选($match)、投射($project)、分组($group)、排序($sort)、限制($limit)、跳过($skip)
    不同的管道操作符可以任意组合,重复使用
    
    • 准备数据
    from pymongo import MongoClient
    import datetime
    
    client=MongoClient('mongodb://root:123@localhost:27017')
    table=client['db1']['emp']
    # table.drop()
    
    l=[
    ('tom','male',18,'20170301','校长',73000.33,401,1), #以下是教学部
    ('bob','male',78,'20150302','teacher',10000.31,401,1),
    ('sam','male',81,'20130305','teacher',8300,401,1),
    ('zhang3','male',73,'20140701','teacher',3500,401,1),
    ('li4','male',28,'20121101','teacher',2100,401,1),
    ('may','female',18,'20110211','teacher',9000,401,1),
    ('wang5','male',18,'19000301','teacher',30000,401,1),
    ('成龙','male',48,'20101111','teacher',10000,401,1),
    
    ('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门
    ('丫丫','female',38,'20101101','sale',2000.35,402,2),
    ('丁丁','female',18,'20110312','sale',1000.37,402,2),
    ('星星','female',18,'20160513','sale',3000.29,402,2),
    ('格格','female',28,'20170127','sale',4000.33,402,2),
    
    ('张野','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门
    ('程咬金','male',18,'19970312','operation',20000,403,3),
    ('程咬银','female',18,'20130311','operation',19000,403,3),
    ('程咬铜','male',18,'20150411','operation',18000,403,3),
    ('程咬铁','female',18,'20140512','operation',17000,403,3)
    ]
    
    for n,item in enumerate(l):
        d={
            "_id":n,
            'name':item[0],
            'sex':item[1],
            'age':item[2],
            'hire_date':datetime.datetime.strptime(item[3],'%Y%m%d'),
            'post':item[4],
            'salary':item[5]
        }
        table.save(d)
    
    • 筛选:$match
    {"$match":{"字段":"条件"}},可以使用任何常用查询操作符$gt,$lt,$in#例1、select * from db1.emp where post='teacher';
    db.emp.aggregate({"$match":{"post":"teacher"}})
    
    #例2、select * from db1.emp where id > 3 group by post;  
    db.emp.aggregate(
        {"$match":{"_id":{"$gt":3}}},
        {"$group":{"_id":"$post",'avg_salary':{"$avg":"$salary"}}}
    )
    
    #例3、select * from db1.emp where id > 3 group by post having avg(salary) > 10000;  
    db.emp.aggregate(
        {"$match":{"_id":{"$gt":3}}},
        {"$group":{"_id":"$post",'avg_salary':{"$avg":"$salary"}}},
        {"$match":{"avg_salary":{"$gt":10000}}}
    )
    
    • 投射:$project
    {"$project":{"要保留的字段名":1,"要去掉的字段名":0,"新增的字段名":"表达式"}}
    
    #1、select name,post,(age+1) as new_age from db1.emp;
    db.emp.aggregate(
        {"$project":{
            "name":1,
            "post":1,
            "new_age":{"$add":["$age",1]}
            }
    })
    
    #2、表达式之数学表达式
    {"$add":[expr1,expr2,...,exprN]} #相加
    {"$subtract":[expr1,expr2]} #第一个减第二个
    {"$multiply":[expr1,expr2,...,exprN]} #相乘
    {"$divide":[expr1,expr2]} #第一个表达式除以第二个表达式的商作为结果
    {"$mod":[expr1,expr2]} #第一个表达式除以第二个表达式得到的余数作为结果
    
    #3、表达式之日期表达式:$year,$month,$week,$dayOfMonth,$dayOfWeek,$dayOfYear,$hour,$minute,$second
    #例如:select name,date_format("%Y") as hire_year from db1.emp
    db.emp.aggregate(
        {"$project":{"name":1,"hire_year":{"$year":"$hire_date"}}}
    )
    
    #例如查看每个员工的工作多长时间
    db.emp.aggregate(
        {"$project":{"name":1,"hire_period":{
            "$subtract":[
                {"$year":new Date()},
                {"$year":"$hire_date"}
            ]
        }}}
    )
    
    
    #4、字符串表达式
    {"$substr":[字符串/$值为字符串的字段名,起始位置,截取几个字节]}
    {"$concat":[expr1,expr2,...,exprN]} #指定的表达式或字符串连接在一起返回,只支持字符串拼接
    {"$toLower":expr}
    {"$toUpper":expr}
    
    db.emp.aggregate( {"$project":{"NAME":{"$toUpper":"$name"}}})
    
    #5、逻辑表达式
    $and
    $or
    $not
    其他见Mongodb权威指南
    
    
    
    • 分组:$group
    {"$group":{"_id":分组字段,"新的字段名":聚合操作符}}
    
    #1、将分组字段传给$group函数的_id字段即可
    {"$group":{"_id":"$sex"}} #按照性别分组
    {"$group":{"_id":"$post"}} #按照职位分组
    {"$group":{"_id":{"state":"$state","city":"$city"}}} #按照多个字段分组,比如按照州市分组
    
    #2、分组后聚合得结果,类似于sql中聚合函数的聚合操作符:$sum、$avg、$max、$min、$first、$last
    #例1:select post,max(salary) from db1.emp group by post; 
    db.emp.aggregate({"$group":{"_id":"$post","max_salary":{"$max":"$salary"}}})
    
    #例2:去每个部门最大薪资与最低薪资
    db.emp.aggregate({"$group":{"_id":"$post","max_salary":{"$max":"$salary"},"min_salary":{"$min":"$salary"}}})
    
    #例3:如果字段是排序后的,那么$first,$last会很有用,比用$max和$min效率高
    db.emp.aggregate({"$group":{"_id":"$post","first_id":{"$first":"$_id"}}})
    
    #例4:求每个部门的总工资
    db.emp.aggregate({"$group":{"_id":"$post","count":{"$sum":"$salary"}}})
    
    #例5:求每个部门的人数
    db.emp.aggregate({"$group":{"_id":"$post","count":{"$sum":1}}})
    
    #3、数组操作符
    {"$addToSet":expr}:不重复
    {"$push":expr}:重复
    
    #例:查询岗位名以及各岗位内的员工姓名:select post,group_concat(name) from db1.emp group by post;
    db.emp.aggregate({"$group":{"_id":"$post","names":{"$push":"$name"}}})
    db.emp.aggregate({"$group":{"_id":"$post","names":{"$addToSet":"$name"}}})
    
    
    
    • 排序:sortsort、限制:limit、跳过:$skip
    {"$sort":{"字段名":1,"字段名":-1}} #1升序,-1降序
    {"$limit":n} 
    {"$skip":n} #跳过多少个文档
    
    #例1、取平均工资最高的前两个部门
    db.emp.aggregate(
    {
        "$group":{"_id":"$post","平均工资":{"$avg":"$salary"}}
    },
    {
        "$sort":{"平均工资":-1}
    },
    {
        "$limit":2
    }
    )
    #例2、
    db.emp.aggregate(
    {
        "$group":{"_id":"$post","平均工资":{"$avg":"$salary"}}
    },
    {
        "$sort":{"平均工资":-1}
    },
    {
        "$limit":2
    },
    {
        "$skip":1
    }
    )
    
    • 随机选取n个:$sample
    #集合users包含的文档如下
    { "_id" : 1, "name" : "dave123", "q1" : true, "q2" : true }
    { "_id" : 2, "name" : "dave2", "q1" : false, "q2" : false  }
    { "_id" : 3, "name" : "ahn", "q1" : true, "q2" : true  }
    { "_id" : 4, "name" : "li", "q1" : true, "q2" : false  }
    { "_id" : 5, "name" : "annT", "q1" : false, "q2" : true  }
    { "_id" : 6, "name" : "li", "q1" : true, "q2" : true  }
    { "_id" : 7, "name" : "ty", "q1" : false, "q2" : true  }
    
    #下述操作时从users集合中随机选取3个文档
    db.users.aggregate(
       [ { $sample: { size: 3 } } ]
    )
    
    展开全文
  • MongoDB是什么?看完你就知道了

    万次阅读 多人点赞 2019-09-03 14:18:19
    最近在回顾mongodb的相关知识,输出一篇文章做为MongoDB知识点的总结。 总结的目的在于回顾MongoDB的相关知识点,明确MongoDB在企业级应用中充当的角色,为之后的技术选型提供一个可查阅的信息简报 一、...

    最近在回顾mongodb的相关知识,输出一篇文章做为MongoDB知识点的总结。
    总结的目的在于回顾MongoDB的相关知识点,明确MongoDB在企业级应用中充当的角色,为之后的技术选型提供一个可查阅的信息简报。

    最新出的姐妹篇《Redis是什么?看完你就知道了》希望大家支持!

    一、概述

    1.MongoDB是什么?用一句话总结

    MongoDB是一款为web应用程序和互联网基础设施设计的数据库管理系统。没错MongoDB就是数据库,是NoSQL类型的数据库

    2.为什么要使用MongoDB?

    (1)MongoDB提出的是文档、集合的概念,使用BSON(类JSON)作为其数据模型结构,其结构是面向对象的而不是二维表,存储一个用户在MongoDB中是这样子的。

    {
    	username:'123',
    	password:'123'
    }
    

    使用这样的数据模型,使得MongoDB能在生产环境中提供高读写的能力,吞吐量较于mysql等SQL数据库大大增强。

    (2)易伸缩,自动故障转移。易伸缩指的是提供了分片能力,能对数据集进行分片,数据的存储压力分摊给多台服务器。自动故障转移是副本集的概念,MongoDB能检测主节点是否存活,当失活时能自动提升从节点为主节点,达到故障转移。

    (3)数据模型因为是面向对象的,所以可以表示丰富的、有层级的数据结构,比如博客系统中能把“评论”直接怼到“文章“的文档中,而不必像myqsl一样创建三张表来描述这样的关系。

    3.主要特性

    (1)文档数据类型
    SQL类型的数据库是正规化的,可以通过主键或者外键的约束保证数据的完整性与唯一性,所以SQL类型的数据库常用于对数据完整性较高的系统。MongoDB在这一方面是不如SQL类型的数据库,且MongoDB没有固定的Schema,正因为MongoDB少了一些这样的约束条件,可以让数据的存储数据结构更灵活,存储速度更加快。

    (2)即时查询能力
    MongoDB保留了关系型数据库即时查询的能力,保留了索引(底层是基于B tree)的能力。这一点汲取了关系型数据库的优点,相比于同类型的NoSQL redis 并没有上述的能力。

    (3)复制能力
    MongoDB自身提供了副本集能将数据分布在多台机器上实现冗余,目的是可以提供自动故障转移、扩展读能力。

    (4)速度与持久性
    MongoDB的驱动实现一个写入语义 fire and forget ,即通过驱动调用写入时,可以立即得到返回得到成功的结果(即使是报错),这样让写入的速度更加快,当然会有一定的不安全性,完全依赖网络。
    MongoDB提供了Journaling日志的概念,实际上像mysql的bin-log日志,当需要插入的时候会先往日志里面写入记录,再完成实际的数据操作,这样如果出现停电,进程突然中断的情况,可以保障数据不会错误,可以通过修复功能读取Journaling日志进行修复。

    (5)数据扩展
    MongoDB使用分片技术对数据进行扩展,MongoDB能自动分片、自动转移分片里面的数据块,让每一个服务器里面存储的数据都是一样大小。

    4.C/S服务模型

    MongoDB核心服务器主要是通过mongod程序启动的,而且在启动时不需对MongoDB使用的内存进行配置,因为其设计哲学是内存管理最好是交给操作系统,缺少内存配置是MongoDB的设计亮点,另外,还可通过mongos路由服务器使用分片功能。

    MongoDB的主要客户端是可以交互的js shell 通过mongo启动,使用js shell能使用js直接与MongoDB进行交流,像使用sql语句查询mysql数据一样使用js语法查询MongoDB的数据,另外还提供了各种语言的驱动包,方便各种语言的接入。

    5.完善的命令行工具

    mongodump和mongorestore,备份和恢复数据库的标准工具。输出BSON格式,迁移数据库。

    mongoexport和mongoimport,用来导入导出JSON、CSV和TSV数据,数据需要支持多格式时有用。mongoimport还能用与大数据集的初始导入,但是在导入前顺便还要注意一下,为了能充分利用好mongoDB通常需要对数据模型做一些调整。

    mongosniff,网络嗅探工具,用来观察发送到数据库的操作。基本就是把网络上传输的BSON转换为易于人们阅读的shell语句。

    因此,可以总结得到,MongoDB结合键值存储和关系数据库的最好特性。因为简单,所以数据极快,而且相对容易伸缩还提供复杂查询机制的数据库。MongoDB需要跑在64位的服务器上面,且最好单独部署,因为是数据库,所以也需要对其进行热备、冷备处理。

    二、进入MongoDB shell

    因为本篇文章不是API手册,所有这里对shell的使用也是基础的介绍什么功能可以用什么语句,主要是为了展示使用MongoDB shell的方便性,如果需要知道具体的MongoDB shell语法可以查阅官方文档。

    1.切换数据库

    use dba
    

    创建数据库并不是必须的操作,数据库与集合只有在第一次插入文档时才会被创建,与对数据的动态处理方式是一致的。简化并加速开发过程,而且有利于动态分配命名空间。如果担心数据库或集合被意外创建,可以开启严格模式

    2.插入语法

    db.users.insert({username:"smith"})
    db.users.save({username:"smith"})
    

    区别
    若新增的数据中存在主键 ,insert() 会提示错误,而save() 则更改原来的内容为新内容。

    如:
    已存在数据: {_id : 1, " name " : " n1 " },再次进行插入操作时,
    insert({_id : 1, " name " : " n2 " }) 会报主键重复的错误提示
    save({ _id : 1, " name " : " n2 " }) 会把 n1 修改为 n2 。
    相同点:
    若新增的数据中没有主键时,会增加一条记录。
    已存在数据: { _id : 1, " name " : " n1 " },再次进行插入操作时,
    insert({ " name " : " n2 " }) 插入的数据因为没有主键,所以会增加一条数据
    save({ " name " : " n2 " }) 增加一条数据。

    3.查找语法

    db.users.find()
    db.users.count()
    

    4.更新语法

    db.users.update({username:"smith"},{$set:{country:"Canada"}})
    //把用户名为smith的用户的国家改成Canada
    
    db.users.update({username:"smith"},{$unset:{country:1}})
    //把用户名为smith的用户的国家字段给移除
    
    db.users.update({username:"jones"},{$set:{favorites:{movies:["casablance","rocky"]}}})
    //这里主要体现多值修改,在favorties字段中添加多个值
    
    db.users.update({"favorites.movies":"casablance"},{$addToSet:{favorites.movies:"the maltese"}},false,true)
    //多项更新
    

    5.删除语法

    db.foo.remove() //删除所有数据
    db.foo.remove({favorties.cities:"cheyene"}) //根据条件进行删除
    db.drop() //删除整个集合
    

    6.索引相关语法

    db.numbers.ensureIndex({num:1})
    //创建一个升序索引
    db.numbers.getIndexes()
    //获取全部索引
    

    7.基本管理语法

    show dbs
    //查询所有数据库
    show collections
    //显示所有表
    db.stats()
    //显示数据库状态信息
    db.numbers.stats()
    //显示集合表状态信息
    db,shutdownServer()
    //停止数据库
    db.help()
    //获取数据库操作命令
    db.foo.help()
    //获取表操作命令
    tab 键 //能自动帮我们补全命令
    

    以上的命令只是简单实例,假设如果你之前没有学习过任何数据库语法,同时开始学sql查询语法和MongoDB 查询语法,你会发现哪一个更简单呢?如果你使用的是java驱动去操作MongoDB,你会发现任何的查询都像Hibernate提供出来的查询方式一样,只要构建好一个查询条件对象,便能轻松查询(接下来会给出示例),博主之前熟悉ES6,所以入手MongoDB js shell完成没问题,也正因为这样简洁,完善的查询机制,深深的爱上了MongoDB。

    三、使用java驱动

    使用java驱动链接MongoDB是一件非常简单的事情,简单的引用,简单的做增删改查。在使用完java驱动后我才发现spring 对MongoDB 的封装还不如官方自身提供出来的东西好用,下面简单的展示一下使用。

    1.使用maven引入jar包

    这里引用的是最新的驱动包,提供了一套新的访问连接方式

    		<dependency>
    			<groupId>org.mongodb</groupId>
    			<artifactId>mongodb-driver-sync</artifactId>
    			<version>3.8.0-beta3</version>
    		</dependency>
    

    2.创建一个访问客户端

    MongoClient client = MongoClients.create(“mongodb://10.201.76.94:27017”);
    

    3.获取集合数量

    public long count() {
    		MongoClient client = this.getClient();
    		MongoCollection<Document> collections= client.getDatabase("mongodb_db_name").getCollection("mongodb_collection_name");
    		return collections.count();
    	}
    

    4.查询集合

    public List<Document> find(Document params,Bson sort,int skip,int limit) {
    		MongoClient client = this.getClient();
    		MongoCollection<Document> collections= client.getDatabase("mongodb_db_name").getCollection("mongodb_collection_name");
    		List<Document> list = new ArrayList<Document>(Integer.valueOf(config.getPro("sync_limit")));
    	collections.find(params).sort(sort).skip(skip).limit(limit).forEach(new Block<Document>() {
    			@Override
    			public void apply(Document document) {
    				list.add(document);
    			}
    		});
    		return list;
    	}
    

    这里只举例了简单的链接与简单的MongoDB操作,可见其操作的容易性。使用驱动时是基于TCP套接字与MongoDB进行通信的,如果查询结果较多,恰好无法全部放进第一服务器中,将会向服务器发送一个getmore指令获取下一批查询结果。

    插入数据到服务器时间,不会等待服务器的响应,驱动会假设写入是成功的,实际是使用客户端生成对象id,但是该行为可以通过配置配置,可以通过安全模式开启,安全模式可以校验服务器端插入的错误。

    四、schema 设计原则

    1.需要关注MongoDB的自身的特性

    要清楚了解MongoDB的基本数据单元。在关系型数据库中有带列和行的数据表。而MongoDB数据的基本单元是BSON文档,在键值中有指向不定类型值的键,MongoDB拥有即时查询,但不支持联结操作,简单的键值存储只能根据单个键来获取值,不支持事务,但支持多种原子更新操作。

    2.需要关注系统本身的读写特性

    如读写比是怎样的,需要何种查询,数据是如何更新的,会不会存在什么并发问题,数据结构化的程度是要求高还是低。系统本身的需求决定mysql还是MongoDB

    3.关注MongoDB schema 的设计模式

    (1)内嵌与引用
    当子对象总是出现在父对象的上下文中时,使用内嵌文档;否则将子对象单独存一个集合

    (2)一对多的关系
    在“多”的集合关系中添加id指向依赖的id

    (3)多对多
    在其中一种对应关系中使用对象数组指向另外一个对象

    (4)树
    具化路径,在树中的每个节点都包含一个path字段,该字段具体保存了每个节点祖先的id

    (5)动态属性
    可以为不同的动态属性添加索引,如果需要将属性圈在一个范围,那么可以通过key-value的方式,然后在统一的key上面加索引

    (6)关于事务
    如果需要事务支持,那么只能选择另一种数据库,或者提供补偿性事务来解决事务的问题

    在关于schema 的设计中要注意一些原则,比如

    • 不能创建没用的索引
    • 不能在同一个字段中存不同的类型
    • 不能把多类实体都放在一个集合里 不能创建体积大、嵌套深的文档
    • 不能过多的创建集合,集合、索引、数据库的命名空间都是有限的
    • 不能创建无法分片的集合

    4.关注MongoDB里面一些具体细节

    (1)关注数据库的概念
    数据库是集合的逻辑与物理分组,MongoDB没有提供创建数据库的语法,只有在插入集合时,数据库才开始建立。创建数据库后会在磁盘分配一组数据文件,所有集合、索引和数据库的其他元数据都保存在这些文件中,查阅数据库使用磁盘状态可通过

    db.stats()
    

    (2)关注集合概念
    集合是结构上或概念上相似得文档的容器,集合的名称可以包含数字、字母或 . 符号,但必须以字母或数字开头,完全。
    限定集合名不能超过128个字符,实际上 . 符号在集合中很有用,能提供某种虚拟命名空间,这是一种组织上的原则,和其他集合是一视同仁的。在集合中可以使用。

    system.namespaces //查询当前数据库中定义的所有命名空间
    system.indexes //存储当前数据库的所有索引定义
    

    (3)关注文档
    其次是键值,在MongoDB里面所有的字符串都是UTF-8类型。数字类型包括double、int、long。日期类型都是UTC格式,所以在MongoDB里面看到的时间会比北京时间慢8小时。整个文档大小会限制在16m以内,因为这样可以防止创建难看的数据类型,且小文档可以提升性能,批量插入文档理想数字范围是10~200,大小不能超过16MB。

    五、索引与查询优化

    1.索引的经验法则

    (1)索引能显著减少获取文档的所需工作量,具体的对比可以通过

    .explain()
    

    方法进行对比

    (2)解析查询时MongoDB通过最优计划选择一个索引进行查询,当没有最适合索引时,会先不同的使用各个索引进行查询,最终选出一个最优索引做查询

    (3)如果有一个a-b的复合索引,那么仅针对a的索引是冗余的

    (4)复合索引里的键的顺序是很重要的

    2.索引类型

    (1)单键索引
    (2)复合索引
    (3)唯一性索引
    (4)稀疏索引
    如索引的字段会出现null的值,或是大量文档都不包含被索引的键

    3.索引的构建问题

    如果数据集很大时,构建索引将会花费很长的时间,且会影响程序性能,可通过

    db.currentOp() //查看索引的构建时间
    

    当使用 mongorestore 时会重新构建索引。当曾经执行过大规模的删除时,可使用

     db.values.reIndex() 
    

    对索引进行压缩,重建

    4.识别慢查询

    (1)查阅慢查询日志

    grep -E '([0-9])+ms' mongod.log //使用grep 命令 识别命令信息
    
    db.setProfillingLevel(2) //使用解刨器,将记录每次的读写到日志
    
    db.setProfillingLevel(1) //只记录慢(100ms)操作
    

    (2)分析慢查询

    db.values.find({}).sort({close:-1}).limit(1).explain()
    
    • scanOrder 字段表明没有使用索引
    • cursor当没有索引时,用的是BasicCursor,当使用索引时使用的是BtreeCursor
    • n 表示需要返回的结果集
    • nscanned表示需要遍历的文档数 indexBounds 表示索引边界

    注意新版本的MongoDB 的explain方法是需要参数的,不然只显示普通的信息

    六、MongoDB副本集

    本节同样主要简单呈现MongoDB副本集搭建的简易性,与副本集的强壮性,监控容易性

    1.为什么要使用副本集

    提供主从复制能力,热备能力,故障转移能力

    2.构建方式

    rs.initiate()
    rs.add("localhost:40001")
    rs.add("localhost:40002",{arbiterOnly:true})
    

    3.监控

    db.isMasrter()
    rs.status()
    

    4.副本集的工作原理

    实际上MongoDB对副本集的操作跟mysql主从操作是差不多的,先看一下mysql的主从数据流动过程

    主binlog -> 从relay.log -> 从bin.log -> 从数据库
    

    而MongoDB主要依赖的日志文件是oplog

    主oplog -> 从oplog
    

    写操作先被记录下来,添加到主节点的oplog里。与此同时,所有从结点复制oplog。首先,查看自己oplog里最后一条的时间戳;其次,查询主节点oplog里所有大于此时间戳的条目;最后,把那些条目添加到自己的oplog里并应用到自己的库里。从节点使用长轮询立即应用来自主结点oplog的新条目。

    当遇到以下情况,从节点会停止复制

    • 如果从节点在主节点的oplog里找不到它所同步的点,那么会永久停止复制
    • 一旦某个从节点没能 在主节点的oplog里找到它已经同步的点,就无法再保证这个从结点的完美副本

    local数据库保存了所有副本集元素据和oplog日志

    • replset.minvalid 包含指定副本集成员的初始化同步信息
    • system.replset 保存在副本集配置文档
    • system.indexes 标准索引说明容器
    • me slaves 主要用于写关注

    可以使用以下命令查看复制情况

    db.oplog.rs.findOne()
    
    • ts 保存了该条目的BSON时间戳
    • t 是从纪元开始的描述
    • i是计数器
    • op 表示操作码
    • ns 标明了有关的命名空间

    5.心跳检测

    每个副本集成员每秒钟ping一次其他所有成员,可以通过rs.status()看到节点上次的心跳检测时间戳和健康状况。

    6.故障转移

    这个点没必要过多描述,但是有一个特殊场景,如果从节点和仲裁节点都被杀了,只剩下主节点,他会把自己降级成为从节点。

    7.提交与回滚

    如果主节点的数据还没有写到从库,那么数据不能算提交,当该主节点变成从节点时,便会触发回滚,那些没写到从库的数据将会被删除,可以通过rollback子目录中的BSON文件恢复回滚的内容。

    8.驱动与复制

    (1)使用单节点链接
    只能链接到主节点,如果链接到从节点的话,会被拒绝写入操作,但是如果没有使用安全模式,因为mongo的fire and forget 特性,会把拒绝写入的异常给吃掉。

    (2)使用副本集方式链接
    能根据写入的情况自动进行故障转移,但是当副本集进行新的选举时,还是会出现故障,如果不使用安全模式,依旧会出现写不进去,但现实成功的情况。

    (3)写关注
    可以使用写关注来关注数据是否已经被写入MongoDB的库中,使用写关注会消耗性能,需要在速度和持久性之间做出权衡。

    七、分片

    分片是数据库切分的一个概念实现,这里也是简单总结为什么要使用分片以及分片的原理,操作。

    1.为什么需要分片

    当数据量过大,索引和工作数据集占用的内存就会越来越多,所以需要通过分片负载来解决这个问题

    2.分片的工作原理

    (1)分片组件

    • 分片:每个分片都是一个副本集
    • mongos路由器:是一个路由器,将读写请求指引到合适的分片上
    • 配置服务器config:持久化分片集群的元数据,包括:全局集群配置;每个数据库、集合和特定范围数据位置;一份变更记录,保存了数据在分片之间进行迁移的历史信息。配置服务器之间不是副本集形式存在,mongos向配置服务器提交信息时是两阶段提交,保证配置服务器之间的一致性。

    (2)分片的核心操作
    分片一个集合:分片是根据一个属性的范围进行划分的,MongoDB使用所谓的分片键让每个文档在这些范围里找到自己的位置

    块:是位于一个分片中的一段连续的分片键范围,可以理解为若干个块组成分片,分片组成MongoDB的全部数据

    (3)拆分与迁移
    块的拆分:初始化时只有一个块,达到最大块尺寸64MB或100000个文档就会触发块的拆分。把原来的范围一分为二,这样就有了两个块,每个块都有相同数量的文档。

    迁移:当分片中的数据大小不一时会产生迁移的动作,比如分片A的数据比较多,会将分片A里面的一些块转移到分片B里面去。分片集群通过在分片中移动块来实现均衡,是由名为均衡器的软件进程管理的,任务是确保数据在各个分片中保持均匀分布,当集群中拥有块最多的分片与拥有块最少分片的块差大于8时,均衡器就会发起一次均衡处理。

    3.分片实战

    启动两个副本集、三个配置服务器、一个mongos进程

    配置分片

    sh.help() //查看分片相关帮助
    sh.addShard() //添加分片
    db,getSiblingDB("config").shards.find() //查看分片列表
    sh.status() //分片详情
    sh.enableSharding("cloud-docs") //开启一个数据库上的分片
    db.getSiblingDB("config").databases,find() //查看数据库列表
    sh.shardCollection("cloud-docs.spreadsheets",{username:1,_id:1}) //使用一个分片键定义一个分片集合spreadsheets,根据用户名进行切分
    sh.getSiiblingDB("config").collections.findOne() //查看集合列表
    db.chunks.count() //查看块的个数
    db.chunks.findOne() //查看块的信息
    db.changelog.count(}what:"split"|) //查看块切分日志
    db.changelog.find({what:"moveChunk.commit"}).count() //查看日志迁移记录
    

    4.分片的查询与索引

    (1)分片查询类型

    • 针对性查询:查询包含分片键
    • 全局查询或分散/聚集查:查询不包含分片键
    • 查询过程:通过分片键将查询路由给指定分片,一旦到了某个分片上,由分片自行决定使用哪个索引来执行该查询

    (2)索引
    每个分片都维护了自己的索引,当在分片集合上声明索引时,每个分片都会为它那部分集合构建独立的索引,每个分片上的分片集合都应该拥有相同的索引。

    分片集合只允许在_id字段和分片键上添加唯一性索引,其他地方不行,因为这需要在分片间进行通信,实施起来很复杂。

    当创建分片时,会根据分片键创建一个索引。

    5.选择分片键

    (1)分片键是不可修改的、分片键的选择非常重要
    (2)低效的分片键

    • 分布性差:如使用BSON对象ID,那么会导致所有最新插入的文档都会落到某个很小的连续范围,无法分散插入
    • 缺乏局部性:升序分片键有明确的方向,完全随机的分片键则根本没有方向。前者无法分散插入,后者插入分散,如使用MD5作为分片键

    (3)理想的分片键

    • 将插入数据均匀分布到各个分片上
    • 保证CRUD操作能够利用局部性 有足够的粒度进行块拆分
    • 满足这些要求的分片键通常由两个字段组成,第一个是粗粒度的,第二个粒度较细

    6.生产环境中的分片

    (1)部署拓扑

    • 复制mongod:需要独立的部署服务器
    • 配置服务器:配置服务器不需要有自己的机器

    根据不同的数据中心划分
    这里写图片描述

    (2)最低要求

    • 副本集每个成员,无论是完整的副本集节点还是仲裁节点,都需要放在不同的机器上 每个用于复制的副本集成员都需要有自己的机器
    • 副本集仲裁节点很轻量级,和其他进程共用一台机器即可
    • 配置服务器也可以选择与其他进程共用一台机器

    这里写图片描述

    (3)配置的注意事项
    需要估计集群大小,可使用以下命令对现有集合进行分片处理

    sh.splitAt("cloud-docs.spreadsheets",{"username":"chen","_id":ObjectId("")})
    //手动拆分块
    sh.moveChunk("cloud-docs.spreadsheets",{username:"chen"},"shardB")
    //手动将某分块移至分片B
    db.runCommand({removeshard:"shard-1/arete:30100,arete:30101"}) 
    //删除分片
    db.runCommand({moveprimary:"test",to:"shard-0-test-rs"});
    //移动主分片
    

    (4)备份分片集群
    备份分片时需要停止均衡器

    db.settings.update({_id:"ba;ancer"},{$set:{stopped:true},true});
    sh.setBalancerState(false);
    //停止均衡器,此时均衡器将进行最后一轮均衡
    
    db.locks.find({_id:"balancer"});
    sh.isBalancerRunning();
    //查看均衡器状态,任何状态大于0 的状态值都说明均衡器仍在进行中
    

    八、部署与管理

    1.部署

    (1)部署架构
    使用64位机器、32位机器会制约mongodb的内存,使其最大值为1.5GB

    (2)cpu
    mongodb 只有当索引和工作集都可放入内存时,才会遇到CPU瓶颈,CPU在mongodb使用中的作用是用来检索数据,如果看到CPU使用饱和的情况,可以通过查询慢查询日志,排查是不是查询的问题导致的,如果是可以通过添加索引来解决问题
    mongodb写入数据时会使用到CPU,但是mongodb写入时间一次只用到一个核,如果有频繁的写入行为,可以通过分片来解决这个问题

    (3)内存
    大内存是mongodb的保障,如果工作集大小超过内存,将会导致性能下降,因为这将会增加数据加载入内存的动作

    (4)硬盘
    mongodb默认每60s会与磁盘强制同步一次,称为后台刷新,会产生I/O操作。在重启时mongodb会将磁盘里面的数据加载至内存,高速磁盘将会减少同步的时间

    (5)文件系统
    使用ext4 和 xfs 文件系统
    禁用最后访问时间

    vim /etc/fstab
    

    (6)文件描述符
    linux 默认文件描述符是1024,需要大额度的提升这个额度

    (7)时钟
    mongodb各个节点服务器之间使用ntp服务器

    2.安全

    (1)绑定IP
    启动时使用 - -bind_ip 命令

    (2)身份验证
    启动时使用 - -auth 命令

    db.addUser("","",true)
    //创建用户,最后一个参数指定是否只读
    

    (3)副本集身份认证
    使用keyFile,注意keyFile文件的权限必须是600,不然会启动不起来

    3.数据的导入与导出

    mongoimport
    mongoexport
    

    4.服务器配置

    (1)拓扑结构
    搭建副本集至少需要两个节点,其中仲裁结点不需要有自己的服务器

    (2)Journaling日志
    写数据时会先写入日志,而此时的数据也不是直接写入硬盘,而是写入内存
    但是Journaling日志会消耗内存,所以可以在主库上面关闭,在从库上面启动
    可以单独为Journaling日志使用一块固态硬盘
    在插入时,可以通过驱动确保Journaling插入后再反馈,但是会非常影响性能

    5.日志

    logpath 选项指定日志存储地址
    -vvvvv 选项(v越多,输出越详细)
    db.runCommand({logrotare:1}) 开启滚动日志

    6.数据库监控命令

    (1)serverStatus
    这里写图片描述
    globalLock 表示服务器花在写锁上面的总时间
    mem显示了如何使用内存
    bits 表明这台机器的位长
    resident 表示占用物理内存数量
    virtual 表示使用的虚拟内存

    (2)top
    这里写图片描述

    (3)db.currentOp()
    这里写图片描述

    7.mongostat

    动态展示mongodb活动数据

    8.web控制台

    占用当前mongodb监听端口往上1000号的端口

    9.备份与恢复

    (1)mongodump
    把数据库内容导出成BSON文件,而mongorestore能读取并还原这些文件

    (2)mongorestore
    把导出的BSON文件还原到数据库

    (3)备份原始数据文件
    可以这么做,但是,操作之前需要进行锁库处理 db.runCommand({fsync:1,lock:true})
    db.$cmd.sys.unlock.findOne() 请求解锁操作,但是数据库不会立刻解锁,需要使用db.currentOp()验证

    10.压紧与修复

    (1)修复
    mongd --repair 修复所有数据库
    db.runCommand({repairDatabase:1}) 修复单个数据库
    修复就是根据Jourling文件读取和重写所有数据文件并重建各个索引

    (2)压紧

    db.spreadsheets.reIndex() //重建索引
    db.runCommand({compact:"spreadsheets"}) 
    

    压紧,会重写数据文件,并重建集合的全部索引,需要停机或者在从库上面运行,如果需要在主库上面运行,需要添加force参数 保证加写锁

    11.性能调优

    (1)监控磁盘状态

    iostat
    

    (2)为提升性能检查索引和查询
    总的来说,扫描尽可能少的文档
    保证没有冗余的索引,冗余的索引会占用磁盘空间、消耗更多的内存,在每次写入时还需做更多工作

    (3)添加内存

    db.stats() //查看数据库数据占用大小状态
    

    dataSize 数据大小 和 indexSize 索引大小,如果两者的和大于内存,那么将会影响性能
    storageSize超过dataSize 数据大小 两倍以上,就会因磁盘碎片而影响性能,需要压缩

    这篇文章对我来说非常有帮助,有时候一些知识点忘记都使用这文章回顾,如果也对你有帮助的话

    在这里插入图片描述

    展开全文
  • MongoDB实战之---初级篇

    万人学习 2018-11-27 10:25:02
    本课程环境:MongoDB 3.4.x CentOS 7.x 本课程为初级课程,围绕高阶聚合函数的使用、索引的介绍及原理解析、索引优化、性能优化、副本集搭建及分布式分片集群的搭建和原理解析来对MongoDB进行更深入的学习。 本...
  • C++连接MongoDB的增删查改

    千次阅读 2019-02-25 15:24:43
    1、前置条件需要安装好MongoDB的驱动(mongocxx),mongo跑起来。 2、项目包含相关头文件和库,例如: INCLUDEPATH += "/usr/local/include/mongocxx/v_noabi" INCLUDEPATH += "/usr/local/include...

    1、前置条件需要安装好MongoDB的驱动(mongocxx),mongo跑起来。

    2、项目包含相关头文件和库,例如:

    INCLUDEPATH += "/usr/local/include/mongocxx/v_noabi"
    INCLUDEPATH += "/usr/local/include/bsoncxx/v_noabi"

    LIBS += -L/usr/local/lib/ -lbsoncxx  -lmongocxx

    3、C++代码如下,已经很精简,不废话解释了:

    
    #include <iostream>
    #include <bsoncxx/builder/stream/document.hpp>
    #include <bsoncxx/json.hpp>
    #include <mongocxx/client.hpp>
    #include <mongocxx/instance.hpp>
    
    int main(int, char**) {
        mongocxx::instance inst{};
        mongocxx::client conn{mongocxx::uri{"mongodb://testuser:testpwd@127.0.0.1:27018/testdb"}};
    //注意在Mongodb3.X版本中需要确保testdb存在,并且testuser:testpwd是在testdb库中进行授权的用户
        bsoncxx::builder::stream::document document{};
        auto collection = conn["testdb"]["testcollection"];
        std::cout<<"type:-----------------------------------"<<typeid(collection).name()<<std::endl;
        decltype(collection) col=collection;
        std::cout<<"type:-----------------------------------"<<typeid(col).name()<<std::endl;
    
        document <<"hello"      << "world"
                 <<"name"       <<"csr"
                 <<"No"         <<34
                 <<"3D"         <<bsoncxx::builder::stream::open_array
                                <<48<<32.123456789<<47
                                <<bsoncxx::builder::stream::close_array
                 <<"friends"    <<bsoncxx::builder::stream::open_array
                                <<"zhangsan"<<"lisi"<<"wangwu"
                                <<bsoncxx::builder::stream::close_array
                 <<"address0"    <<bsoncxx::builder::stream::open_document
                        <<"city"<<"shenzhen"
                        <<"nation"<<"china"
                        <<"phone"<<13524531211
                                <<bsoncxx::builder::stream::close_document
                  /*<<bsoncxx::builder::stream::finalize*/;
    
        std::cout<<"the document:"<<bsoncxx::to_json(document) << std::endl;
    
        bsoncxx::builder::stream::document subdocument{};
        subdocument << "city" << "sz"<<"nation"<<"china"<<"pos"<<525346;
    
        document<<"address"<<subdocument;
    
        std::cout<<"the document after subdoc:"<<bsoncxx::to_json(document) << std::endl;
    
        //插入文档
        collection.insert_one(document.view());    
        collection.insert_one(document.view());
        collection.insert_one(document.view());
    
        //全部罗列文档
        auto cursor = collection.find({});
    
        for (auto&& doc : cursor) {
            std::cout << bsoncxx::to_json(doc) << std::endl;
        }
        std::cout<<"\n after insert_one three times  count:"<<collection.count({})<<std::endl;
    
        //删除文档
        collection.delete_one(document.view());
        std::cout<<"\n after delete_one  once count:"<<collection.count({})<<std::endl;
    
    //    collection.delete_many(document.view());
    //    std::cout<<"\n after delete_many  once count:"<<collection.count({})<<std::endl;
    
        //罗列全部数据库
        auto dbcur = conn.list_databases();
        for(auto && db:dbcur){
            std::cout<<bsoncxx::to_json(db)<<std::endl;
        }
    
        std::cout<<std::endl;
        std::cout<<std::endl;
    
    //    collection =conn.database("eos").collection("transaction_traces");
    
        //查找文档
    //    cursor = collection.find({});
    
        //按普通key-volue查找
    //    cursor = collection.find((bsoncxx::builder::basic::make_document(bsoncxx::builder::basic::kvp("actor", "token"))));
    //    cursor = collection.find((bsoncxx::builder::basic::make_document(bsoncxx::builder::basic::kvp("block_num", 4171818))));
    
    
        //按完整数组查找
        bsoncxx::builder::stream::document finddocument{};
    //    finddocument<<"3D"         <<bsoncxx::builder::stream::open_array
    //                               <<48<<32.123456789<<47
    //                               <<bsoncxx::builder::stream::close_array;
        //按数组的一部分内容查找
    //    finddocument<<"3D"         <<48;
    
        //嵌套文档查找
        finddocument<<"address0"    <<bsoncxx::builder::stream::open_document
                                    <<"city"<<"shenzhen"
                                    <<"nation"<<"china"
                                    <<"phone"<<13524531211
                                    <<bsoncxx::builder::stream::close_document;
    
        cursor = collection.find(finddocument.view());
    
    
    
    
    
    //    bsoncxx::builder::stream::document filter_builder;
    //    filter_builder << "stime" << open_document
    //                            << "$lt" << bsoncxx::types::b_date(std::chrono::system_clock::now())
    //                               << close_document
    //                   << "stime" << open_document
    //                                << "$gt" << bsoncxx::types::b_date(std::chrono::system_clock::now() - std::chrono::seconds{ 600 })
    //                                << close_document
    //                    << "iscancel" << 0
    //                    << "gid" << strGId;
    //    //相当于sql语句:SELECT   * FROM bak__user_order WHERE gid=“2423seef”
    //    //                                            and iscancel=0
    //    //                                            AND add_time < 1514233574
    //    //                                             and add_time >=1514233574
    
    
    
        int flag=0;
    
        for(auto&& doc : cursor/*collection.find(bsoncxx::builder::basic::make_document(bsoncxx::builder::basic::kvp("block_num", 3120204)))*/){
    
    //        bsoncxx::to_json(doc);
            std::cout<<++flag<<"(find):"<<std::endl<<bsoncxx::to_json(doc) << std::endl;
        }
        if(flag==0)
            std::cout<<"\nnot found!!!"<<std::endl;
    
    
        std::cout<<"count:"<<collection.count({})<<std::endl;
    
    }

     

    展开全文
  • 2. mongocxx 续上一篇,接着看一下mongocxx中的文件有些什么。 先看一下基本的增删改查操作: 2.1 connect.cpp 数据库的链接 参见之前的博客。...构造一个文档,插入数据库中的一个collection。...#include
  • 一、什么是MongoDB ? MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。 在高负载的情况下,添加更多的节点,可以保证服务器性能。 MongoDB 旨在为WEB应用提供可扩展的高性能数据...
  • MongoDB一步一步学开发》(Windows10) 六、插入第一个文档 插入文档语法格式 MongoDB 使用 insert() 或 save() 方法向集合中插入文档,语法如下: db.COLLECTION_NAME.insert(document) db.COLLECTION...
  • 部分内容摘自runoob.comMongoDB简介MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。 在高负载的情况下,添加更多的节点,可以保证服务器性能。 MongoDB 旨在为WEB应用提供可扩展的高性能...
  • MongoDB 优缺点

    万次阅读 2018-03-22 15:13:24
    mongodb与关系型数据库相比的优缺点与关系型数据库相比,MongoDB的优点:①弱一致性(最终一致),更能保证用户的访问速度:举例来说,在传统的关系型数据库中,一个COUNT类型的操作会锁定数据集,这样可以保证得到...
  • 什么是MongoDB ? MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。 MongoDB 可在高负载的情况下,添加更多的节点,可以保证服务器性能。 MongoDB 可为Web应用提供可扩展的高性能数据存储...
  • MongoDB基础篇:MongoDB Shell命令大全

    万次阅读 2019-07-29 18:41:12
    要想能熟练操作MongoDB,首先先要熟练使用 MongoDB Shell, 再次要熟练使用驱动 mongodb-java-driver, 最后是spring-data-mongodb的使用 在使用Shell中的方法时,注意很多方法都是有重载函数的一:启动服务和连接...
  • MongoDB安装(超详细)

    万次阅读 多人点赞 2020-04-05 14:53:17
    一、概要 之所以写这篇文章是被mongodb安装坑了不少,接下来我会详细的一步步说明我的安装...一个是可视化界面(解释:你下了MongoDB服务当然要用起来啊,固然你可以使用命令行的客户端,但是建议你安装MongoDB ...
  • linux mongodb安装和配置启动图文详解

    万次阅读 2017-04-25 09:01:23
    一.前期准备 1.Win7环境下 官网下载Mongodb包 本文使用mongodb-linux-...1.解压和复制mongodb至目录 /usr/local/mongodb cd /opt/software tar -zxvf mongodb-linux-x86_64-3.2.12.tgz cp -r mongodb-linux-x86_64-3
  • Windows系统 MongoDB 各个64位版本下载地址

    万次阅读 多人点赞 2016-11-22 14:20:30
    MongoDB Windows系统各个64位版本下载地址: http://dl.mongodb.org/dl/win32/x86_64 MongoDB Windows系统各个64位版本下载地址: http://dl.mongodb.org/dl/win32/x86_64
  • 完全卸载mongodb

    万次阅读 2018-10-16 18:08:16
    sudo apt-get purge mongodb 或者 sudo apt-get purge --auto-remove mongodb
  • 使用MongoDB命令连接远程服务器的MongoDB数据库 MongoDB连接远程服务器的命令格式如下: mongo 远程主机ip或DNS:MongoDB端口号/数据库名 -u user -p password MongoDB连接远程服务器的命令示例代码如下: ...
  • Linux以tar包方式安装MongoDB-4.2.8

    万次阅读 2020-06-28 13:15:03
    tar -zxvf mongodb-linux-x86_64-4.2.8.tgz 创建目录,设置权限 在根目录 / 下创建data/db目录,用于放置mongodb数据,并且给该目录设置权限 sudo mkdir -p /data/db sudo chown -R 自己电脑的用户名 /data ...
  • 关于MongoDB的默认路径(Ubuntu)

    万次阅读 2017-09-27 17:00:15
    MongoDB默认数据文件路径/var/lib/mongodb/MongoDB默认日志文件路径/var/log/mongodb/mongodb.logMongoDB可执行文件路径/usr/bin/mongo /usr/bin/mongod收几个参考博客链接备用 mongodb参考1 mongodb参考2 自启动...
1 2 3 4 5 ... 20
收藏数 214,380
精华内容 85,752
关键字:

mongodb