• MongoDB 学习笔记


    MongoDB简介
          MongoDB是一个基于 分布式文件存储 的数据库。由 C++ 语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
      MongoDB是一个介于 关系数据库 和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 json 的 bson 格  式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立 索引
     
    通过下图实例,我们也可以更直观的了解Mongo中的一些概念:
     
                        
    特点
      它的特点是高性能、易部署、易使用,存储数据非常方便。主要功能特性有:
      *面向集合存储,易存储对象类型的数据。
      *模式自由。
      *支持动态查询。
      *支持完全索引,包含内部对象。
      *支持查询。
      *支持复制和故障恢复。
      *使用高效的二进制数据存储,包括大型对象(如视频等)。
      *自动处理碎片,以支持云计算层次的扩展性。
      *支持 GolangRUBYPYTHONJAVAC++PHPC#等多种语言。
      *文件存储格式为BSON(一种JSON的扩展)。
      *可通过网络访问。
    使用原理
      所谓“面向集合(Collection-Oriented),意思是数据被分组存储在数据集中,被称为一个集合(Collection)。每个集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似关系型数据库(RDBMS)里的表(table),不同的是它不需要定义任何模式(schema)。
      模式自由(schema-free),意味着对于存储在mongodb数据库中的文件,我们不需要知道它的任何结构定义。如果需要的话,你完全可以把不同结构的文件存储在同一个数据库里。
      存储在集合中的文档,被存储为键-值对的形式。键用于唯一标识一个文档,为字符串类型,而值则可以是各种复杂的文件类型。我们称这种存储形式为BSON(Binary Serialized Document Format)
     
    MongoDB已经在多个站点部署,其主要场景如下:
      1)网站实时数据处理。它非常适合实时的插入、更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
      2)缓存。由于性能很高,它适合作为信息基础设施的缓存层。在系统重启之后,由它搭建的持久化缓存层可以避免下层的数据源过载。
      3)高伸缩性的场景。非常适合由数十或数百台服务器组成的数据库,它的路线图中已经包含对MapReduce引擎的内置支持。
    不适用的场景如下:
      1)要求高度事务性的系统。
      2)传统的商业智能应用。
      3)复杂的跨文档(表)级联查询。


      举例
      

      mysql采用table和结构化的sql语句来处理数据,需要预先定义字段名,数据结构,并定义表中数据字段的关系

      mongoDB采用类JSON的documents来存储数据,采用动态数据模型,类似于字典,不需要预先定义表的数据类型和字段名,也就是说可以轻松增加新的字段名或者删除旧的字       段 。

    设计特征
    MongoDB 的设计目标是高性能、可扩展、易部署、易使用,存储数据非常方便。其主要功能特性如下。
    (1)面向集合存储,容易存储对象类型的数据。在MongoDB 中数据被分组存储在集合中,集合类似RDBMS 中的表,一个集合中可以存储无限多的文档。
    (2)模式自由,采用无模式结构存储。在MongoDB 中集合中存储的数据是无模式的文档,采用无模式存储数据是集合区别于RDBMS 中的表的一个重要特征。
          (3)支持完全索引,可以在任意属性上建立索引,包含内部对象。MongoDB的索引和RDBMS 的索引基本一样,可以在指定属性、内部对象上创建索引以提高查询的速度。除此     之外,MongoDB 还提供创建基于地理空间的索引的能力。
          (4)支持查询。MongoDB 支持丰富的查询操作,MongoDB 几乎支持SQL中的大部分查询。
          (5)强大的聚合工具。MongoDB 除了提供丰富的查询功能外,还提供强大的聚合工具,如count、group 等,支持使用MapReduce 完成复杂的聚合任务。
          (6)支持复制和数据恢复。MongoDB 支持主从复制机制,可以实现数据备份、故障恢复、读扩展等功能。而基于副本集的复制机制提供了自动故障恢复的功能,确保了集群数据  不会丢失。
          (7)使用高效的二进制数据存储,包括大型对象(如视频)。使用二进制格式存储,可以保存任何类型的数据对象。
          (8)自动处理分片,以支持云计算层次的扩展。MongoDB 支持集群自动切分数据,对数据进行分片可以使集群存储更多的数据,实现更大的负载,也能保证存储的负载均衡。
          (9)支持Perl、PHP、Java、C#、JavaScript、Ruby、C 和C++语言的驱动程序,MongoDB 提供了当前所有主流开发语言的数据库驱动包,开发人员使用任何一种主流开发语言  都可以轻松编程,实现访问MongoDB 数据库。
          (10)文件存储格式为BSON(JSON 的一种扩展)。BSON 是对二进制格式的JSON 的简称,BSON 支持文档和数组的嵌套。
          (11)可以通过网络访问。可以通过网络远程访问MongoDB 数据库。
    基本概念
    1. 数据库 

      一个mongodb中可以建立多个数据库。

      MongoDB的默认数据库为"db",该数据库存储在data目录中。

      MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。

      MongoDB 中存在以下系统数据库。
      ●  Admin 数据库:一个权限数据库,如果创建用户的时候将该用户添加到admin 数据库中,那么该用户就自动继承了所有数据库的权限。
      ●  Local 数据库:这个数据库永远不会被复制,可以用来存储本地单台服务器的任意集合。
      ●  Config 数据库:当MongoDB 使用分片模式时,config 数据库在内部使用,用于保存分片的信息。
    2. 文档
      文档是 MongoDB 中数据的基本单位,类似于关系数据库中的行(但是比行复杂)。多个键及其关联的值有序地放在一起就构成了文档。
      文档是一组键值(key-value)对(即 BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点
      例如:
           {“greeting”:“hello,world”}
           这个文档只有一个键“greeting”,对应的值为“hello,world”。多数情况下,文档比这个更复杂,它包含多个键/值对。例如:
                {“greeting”:“hello,world”,“foo”: 3}
           文档中的键/值对是有序的,下面的文档与上面的文档是完全不同的两个文档。
               {“foo”: 3 ,“greeting”:“hello,world”}

      需要注意的是:

      1. 文档中的键/值对是有序的。
      2. 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
      3. MongoDB区分类型和大小写。
      4. MongoDB的文档不能有重复的键。
      5. 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。

      文档键命名规范:

      • 键不能含有 (空字符)。这个字符用来表示键的结尾。
      • .和$有特别的意义,只有在特定环境下才能使用。
      • 以下划线"_"开头的键是保留的(不是严格要求的)。
    3. 集合

      集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统)中的表格。

      集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。

      比如,我们可以将以下不同数据结构的文档插入到集合中:

      {"site":"www.baidu.com"}
      {"site":"www.google.com","name":"Google"}
      {"site":"www.runoob.com","name":"菜鸟教程","num":5}

      当第一个文档插入时,集合就会被创建。

      合法的集合名

      • 集合名不能是空字符串""。
      • 集合名不能含有字符(空字符),这个字符表示集合名的结尾。
      • 集合名不能以"system."开头,这是为系统集合保留的前缀。
      • 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。
    数据类型
    数据类型描述
    String 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。
    Integer 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。
    Boolean 布尔值。用于存储布尔值(真/假)。
    Double 双精度浮点值。用于存储浮点值。
    Min/Max keys 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。
    Array 用于将数组或列表或多个值存储为一个键。
    Timestamp 时间戳。记录文档修改或添加的具体时间。
    Object 用于内嵌文档。
    Null 用于创建空值。
    Symbol 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。
    Date 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。
    Object ID 对象 ID。用于创建文档的 ID。
    Binary Data 二进制数据。用于存储二进制数据。
    Code 代码类型。用于在文档中存储 JavaScript 代码。
    Regular expression 正则表达式类型。用于存储正则表达式。
    怎么用? 

    $lt

    小于

    {'age': {'$lt': 20}}

    $gt

    大于

    {'age': {'$gt': 20}}

    $lte

    小于等于

    {'age': {'$lte': 20}}

    $gte

    大于等于

    {'age': {'$gte': 20}}

    $ne

    不等于

    {'age': {'$ne': 20}}

    $in

    在范围内

    {'age': {'$in': [20, 23]}}

    $nin

    不在范围内

    {'age': {'$nin': [20, 23]}}

    $regex

    匹配正则表达式

    {'name': {'$regex': '^M.*'}}

    name以M开头

    $exists

    属性是否存在

    {'name': {'$exists': True}}

    name属性存在

    $type

    类型判断

    {'age': {'$type': 'int'}}

    age的类型为int

    $mod

    数字模操作

    {'age': {'$mod': [5, 0]}}

    年龄模5余0

    $text

    文本查询

    {'$text': {'$search': 'Mike'}}

    text类型的属性中包含Mike字符串

    $where

    高级条件查询

    {'$where': 'obj.fans_count == obj.follows_count'}

    自身粉丝数等于关注数

    $ type 的用法

    $type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果。

    MongoDB 中可以使用的类型如下表所示:

    类型数字备注
    Double 1  
    String 2  
    Object 3  
    Array 4  
    Binary data 5  
    Undefined 6 已废弃。
    Object id 7  
    Boolean 8  
    Date 9  
    Null 10  
    Regular Expression 11  
    JavaScript 13  
    Symbol 14  
    JavaScript (with scope) 15  
    32-bit integer 16  
    Timestamp 17  
    64-bit integer 18  
    Min key 255 Query with -1.
    Max key 127  

    数据库连接

    import pymongo
    
    # 连接                        mongodb://admin:123456@localhost:27017/test
    myclient = pymongo.MongoClient("mongodb://localhost:27017/")
    # 指定数据库
    mydb = myclient["runoobdb"]  # 不存在则创建
    # 判断数据库是否存在
    print("runoobdb" in myclient.list_database_names())
    # 指定集合
    mycol = mydb["sites"]   # 不存在则创建,但是只有在内容插入后才会被真正创建
    # 判断集合是否存在
    print("sites" in mydb.list_collection_names())
    添加数据
    # 插如一条记录
    x1 = mycol.insert_one({ "name": "Google", "alexa": "1", "url": "https://www.google.com" })
    # 打印这条数据的 id
    print(x1.inserted_id)
    # 插入多条记录,并指定id
    mylist = [
      { "_id": 1, "name": "RUNOOB", "address": "菜鸟"},
      { "_id": 2, "name": "Google", "address": "Google 搜索"},
      { "_id": 3, "name": "Facebook", "address": "脸书"},
      { "_id": 4, "name": "Taobao", "address": "淘宝"},
      { "_id": 5, "name": "Zhihu", "address": "知乎"}
    ]
    x = mycol.insert_many(mylist)
    # 输出插入的所有文档对应的 _id 值
    print(x.inserted_ids)
    
    # TODO  没有指定 id 值的数据可以重复擦入,系统会自动生成唯一的 id 值,指定 id 值的数据不能重复插入
    添加数组
    mycol = mydb["grid"]
    #
    f = nc.Dataset(r'C:UsersxixiDocumentsFsdownloadwen_chkkl_ewenEWEN_REAL_GROUND_STATION_OBS_20201206002000.nc', 'r')
    var_key = list(f.variables.keys())
    sta = f.variables['sta'][:]
    lat = f.variables['lat'][:]
    lon = f.variables['lon'][:]
    prs = f.variables['PRS'][:]
    tem = f.variables['TEM'][:]
    
    print(var_key)
    print(sta)
    data = []
    for i,v in enumerate(sta):  # 添加数据类型 float  np类型不行
        d = {'_id':int(v), 'lat': float('%s' % lat[i]), 'lon':float('%s' %lon[i]), 'prs':float('%s' %prs[i]), 'tem':float('%s' %tem[i])}
        data.append(d)
    f.close()
    print(data[1])
    
    data=[{
        '_id':20201206002000,
        'lat':lat.tolist(),
        'lon':lon.tolist(),
        'prs':prs.tolist(),
        'tem':tem.tolist(),
    
    }]
    
    
    x = mycol.insert_many(data)
    print(len(x.inserted_ids))
    查询数据
    # 查询查询一条数据
    x = mycol.find_one()
    print(x)
    # 查询集合中所有数据
    x = [i for i in mycol.find()]
    print(x)
    #   选择列是否输出   1 输出  0 不输出
    #   除了 _id ,你不能在一个对象中同时指定 0 和 1,如果你设置了一个字段为 0,则其他都为 1,反之亦然
    for x in mycol.find({},{ "_id": 0, "name": 1, "alexa": 1 }):
      print(x)
    # 查询字段  指定类型   2 代表 string
    print([i for i in mycol.find({'alexa':{'$type': 2}})])
    print([i for i in mycol.find({'alexa':{'$type': 'string'}})])
    # 模糊查询  写法适用于  cmd命令行  (代码可以用正则)
    db.col.find({title':/M/})   # 中间有 M 
    db.col.find({title':/^M/})  # 以 M 开头
    db.col.find({title':/M$/})  # 以 M 结尾

    # 查询 指定字段名
    myquery = {"name": "RUNOOB"}
    mydoc = mycol.find(myquery)
    print([i for i in mydoc])
    # 条件查询,id > 2 并且 alexa=123 或 name = yitianqi
    # myquery = {"_id": {'$gt':2}, '$or':[{'alexa':'123'}, {'name':'yitianqi'}]}
    myquery = {"_id": {'$gt':2}, '$or':[{'alexa':123}, {'alexa':222}]}
    mydoc = mycol.find(myquery)
    print([i for i in mydoc])
    # 查询 指定字段名的集合
    myquery = {"name": {'$in':["RUNOOB", 'Google']}}
    mydoc = mycol.find(myquery, {"_id": 0, "name": 1, "alexa": 1})
    print([i for i in mydoc])
    # 返回指定条数记录  skip 跳过前 2 条
    for i in mycol.find().skip(2).limit(1):
        print(i)
    
    
    聚合查询
    # $match: 查找条件匹配
    # $project: 字段筛选, 也可以用来重命名字段
    # $group: 集合规则(_id: 需要分类的字段, count:求和,计算总数)
    # $sort: 排序
    # $limit    限制管道输出的结果个数
    # $skip    跳过制定数量的结果,并且返回剩下的结果
    # $unwind    将数组类型的字段进行拆分
    
    # 指定集合
    mycol = mydb["surf"]   # 不存在则创建,但是只有在内容插入后才会被真正创建
    
    x = mycol.aggregate([
        {'$match':{'surf_chn_basic_info_id':'54654'}},
        {'$group': {"_id": "$surf_chn_basic_info_id", 'max_t': {'$max': '$observe_time'}}},
        {'$project': {"_id": 0, "max_t": 1}},
    ])
    print([i for i in x])
    
    
    mycol = mydb["sites"]
    # 查询最大
    x = mycol.find().sort('alexa', -1).limit(1)
    print([i for i in x])
    
    x = mycol.aggregate([
        {'$match':{'name':'Google'}},
        {'$group': {"_id": "$name", 'max_t': {'$max': '$alexa'}}},  # {'_id': {'fName':'$fName','user':'$user'}},
        # {'$limit':1}
    ])
    
    print([i for i in x])
    修改数据
    # 调用 update_one() 方法修改文档中的记录。该方法第一个参数为查询的条件,第二个参数为要修改的字段。
    # 如果查找到的匹配数据多于一条,则只会修改第一条
    myquery = {"_id": 2}
    newvalues = {"$set": {"alexa": 222}}
    
    x = mycol.update_one(myquery, newvalues)   # upsert  如果不存在update的记录, 则插入为新记录
    print(x.matched_count, x.modified_count, "文档已修改")
    # 调用update_many()方法,则会将所有符合条件的数据都更新
    # 使用正则($regex)将查找所有以 F 开头的 name 字段,并将匹配到所有记录的 alexa 字段修改为 123
    myquery = {"name": {"$regex": "^F"}}
    newvalues = {"$set": {"alexa": 123}}
    
    x = mycol.update_many(myquery, newvalues)  # 它会自动判断是否已经为 123 ,如果已经都为 123 则,打印的修改数为 0
          # 匹配的数据条数      影响的数据条数
    print(x.matched_count, x.modified_count, "文档已修改")
    
    
    排序数据
    # 对字段 alexa 按升序排序
    mydoc = mycol.find().sort("alexa")  
    for x in mydoc:
      print(x)
    # 对字段 alexa 按降序排序
    mydoc = mycol.find().sort("alexa", -1)  
    for x in mydoc:
      print(x)
    删除数据
    # 删除name==Taobao的记录
    myquery = {"name": "Taobao"}
    mycol.delete_one(myquery)
    
    # 删除正则表达式 name 以 F 开头的记录
    myquery = {"name": {"$regex": "^F"}}
    x = mycol.delete_many(myquery)
    print(x.deleted_count, "个文档已删除")
    
    # 删除集合中的所有数据
    mycol.delete_many({})
    删除集合
    # 如果删除成功 drop() 返回 true,如果删除失败(集合不存在)则返回 false
    mycol.drop()
    创建索引
    # background 后台执行创建  unique 是否唯一  name 索引名  expireAfterSeconds 指定一个以秒为单位的数值,设定集合的生存时间
    ds = mycol.create_index([("name", pymongo.ASCENDING)], background=True)
    print(ds)   # 返回索引名
    # 查看集合索引
    # db.col.getIndexes()
    # 查看集合索引大小
    # db.col.totalIndexSize()
    # 删除集合所有索引
    # db.col.dropIndexes()
    # 删除集合指定索引
    # db.col.dropIndex("索引名称")
    
    
    # 利用 TTL 集合对存储的数据进行失效时间设置:经过指定的时间段后或在指定的时间点过期,MongoDB 独立线程去清除数据。类似于设置定时自动删除任务,
    # 可以清除历史记录或日志等前提条件,设置 Index 的关键字段为日期类型 new Date()。
    
    # 例如数据记录中 createDate 为日期类型时:
    #   设置时间180秒后自动清除。
    #   设置在创建记录后,180 秒左右删除。
    # db.col.createIndex({"createDate": 1},{expireAfterSeconds: 180})
    # 由记录中设定日期点清除。
    # 设置 A 记录在 2019 年 1 月 22 日晚上 11 点左右删除,A 记录中需添加 "ClearUpDate": new Date('Jan 22, 2019 23:00:00'),且 Index中expireAfterSeconds 设值为 0。
    
    # db.col.createIndex({"ClearUpDate": 1},{expireAfterSeconds: 0})
    # 其他注意事项:
    #  索引关键字段必须是 Date 类型。
    #  非立即执行:扫描 Document 过期数据并删除是独立线程执行,默认 60s 扫描一次,删除也不一定是立即删除成功。
    #  单字段索引,混合索引不支持

    代码仅供参考,欢迎评论交流

     

  • 相关阅读:
    [原] 秋叶原随景
    ReportViewer不连接数据库,自定义DataSet导出到报表
    【程序人生】一个程序员对学弟学妹建议(转)
    c#钩子学习笔记(一)
    解决关于多客户端操作数据库并发问题
    SQL Server 存储过程
    有关抽奖的一个算法
    c#发送邮件含附件
    CrystalReport不连接数据库,自定义DataSet导出到水晶报表
    c#钩子学习笔记(二)
  • 原文地址:https://www.cnblogs.com/luochunxi/p/14155961.html
Copyright © 2020-2023  润新知