• MongoDB


    前言

    我们对一些关系型数据库肯定不会陌生,比如Oracle、MySQL、SQL Server、SQLite 、PostgreSQL。

    什么是SQL?

    SQL:结构化查询语言(Structured Query Language)简称SQL,用户使用SQL操作管理数据库系统。

    什么是NoSQL?

    Not Only SQL 非关系型数据库的意思,它和关系型数据库的区别是:不需要使用SQL去查询数据库内容。

    NoSQL没有Table和Filed这些概念,所以数据和数据之间也不存在任何关联关系(1对1、1对多、多对多),每条记录的列可以不一致。

    NoSQL数据库的操作都是通过指令/程序语言完成的。

    没有了SQL我们如何操作管理MongoDB?

    以上我们得知MySQL使用SQL操作管理数据数据库系统。

    MongoDB使用JavaScript语法、JSON数据结构来操作管理数据库。

    这样以来MongoDB的查询指令和前端JavaScript的数据JSON 进行了数据类型统一 

    后端程序接收到前端传来的JSON数据,无需复杂处理,直接把JSON数据当做MySQL中的SQL一样去执行就能从数据库中返回查询结果,所以MongoDB很适用于web开发

    MongoDB和redis的区别?

    MongoDB是1个使用C++编写的;1个NoSQL文档型数据库,MongoDB有点像关系型数据,它支持组合/分组聚合查询,而Redis是key,value存储。

    MongoDB为什么比MySQL更加灵活?

    关系型数据库表中的列基本固定很难扩展,而在MobgoDB中存储的文就是各种不同的json对象,所以列可以进行灵活扩展,在{}里加个key的事

    MongoDB应用场景?

    如果我们要开发的是1个新的web项目,它的功能后期会不断迭代,无法确定1个具体的数据模型不妨试试MongoDB。

    我们可以使用MongoDB存储 工单信息、运维审计日志、报警信息,我认为MongoDB适用于无法确定表结构、高并发量、 读写频繁对事务要求较低的开发场景。

    MongoDB中的概念

    1.数据库(Database):相当于关系型数据存数据库                                        

    2.集合(Collection):数据库中有集合(collection),相当于关系型数据库中表的概念。

    3.文档(Document):文档数据库中最小单位,也就是各种各样的json。相当于关系型数据库中记录的概念。

     

    安装MongoDB

    1.配置MongoDB的yum源

    vim /etc/yum.repos.d/mongodb-org-3.4.repo
    #添加以下内容:
    [mongodb-org-3.4]  
    name=MongoDB Repository  
    baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/  
    gpgcheck=1  
    enabled=1  
    gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc
    
    #这里可以修改 gpgcheck=0, 省去gpg验证
    [root@localhost ~]# yum makecache      

    2.yum 安装MongoDB

    yum -y install mongodb-org

     

    3.配置mongoDB

    mkdir -p /data/mongo
    chown -R mongod /data/mongo

    配置MongoDB的存储和日志路径以及监听端口

    # mongod.conf
    # for documentation of all options, see:
    #   http://docs.mongodb.org/manual/reference/configuration-options/
    
    # where to write logging data.
    systemLog:
      destination: file
      logAppend: true
      path: /var/log/mongodb/mongod.log
    
    # Where and how to store data.
    storage:
      dbPath: /data/mongo
      journal:
        enabled: true
    #  engine:
    #  mmapv1:
    #  wiredTiger:
    
    # how the process runs
    processManagement:
      fork: true  # fork and run in background
      pidFilePath: /var/run/mongodb/mongod.pid  # location of pidfile
    
    # network interfaces
    net:
      port: 27017
      bindIp: 0.0.0.0  # Listen to local interface only, comment to listen on all interfaces.
    
    
    #security:
    
    #operationProfiling:
    
    #replication:
    
    #sharding:
    
    ## Enterprise-Only Options
    
    #auditLog:
    
    #snmp:

    操作数据库

    1.查看现有数据库

    > show databases;
    admin  0.000GB
    local  0.000GB
    > show dbs;
    admin  0.000GB
    local  0.000GB

    2.创建数据库

    > use web;
    switched to db web
    > show dbs            //注意如果数据库中没有Collections数据库不会显示。
    admin  0.000GB
    local  0.000GB

    3.创建集合(collection)

    > db.createCollection("blogs")
    { "ok" : 1 }
    > show dbs
    admin  0.000GB
    local  0.000GB
    web    0.000GB
    > show collections
    blogs

    4.查看当前数据库的状态

    > db.stats()
    {
        "db" : "web",
        "collections" : 1,
        "views" : 0,
        "objects" : 0,
        "avgObjSize" : 0,
        "dataSize" : 0,
        "storageSize" : 4096,
        "numExtents" : 0,
        "indexes" : 1,
        "indexSize" : 4096,
        "ok" : 1
    }

    5.删库跑路

    > db.dropDatabase()
    { "dropped" : "web", "ok" : 1 }
    > show dbs
    admin  0.000GB
    local  0.000GB
    > exit
    bye

    操作集合(Collection)

    //创建集合
    > db.createCollection("blog") //重命名集合
    > db.blog.renameCollection("blogs") //展示集合
    > show collections //删除集合
    > db.blogs.drop(); > show collections > db.dropDatabase();

    操作文档

    1.insert文档

    > db.blogs.insert(
    ... {
    ... title:"我的第一篇博客",
    ... content:"已经开始写博客了好激动呀!!!"
    ... }
    ... );
    WriteResult({ "nInserted" : 1 })
    

    2.find查看所有文档

    > db.blogs.find();
    { "_id" : ObjectId("60160d64999c1f14d31784e8"), "title" : "我的第1篇博客", "content" : "已经开始写博客了好激动呀!!!" }
    { "_id" : ObjectId("60160e74999c1f14d31784e9"), "title" : "我的第2篇博客,我会玩MongoDB啦!好激动呀!!!" }
    { "_id" : ObjectId("60160f03999c1f14d31784ea"), "title" : "我的第3篇博客,写点什么好呢????", "tag" : "情感" }
    > 

    此时我们发现MongoDB的灵活性,以上3条记录的列均不一样,而关系型数据库中所有记录的列是固定和一致的,这些约束限制了我们的数据结构

    3.排序显示

    升序sort({ _id:1})

    > db.blogs.find({},{_id:0}).sort({_id:1})
    { "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "Linux" }
    { "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" }
    { "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
    { "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" }
    { "title" : "Golang的指针", "rank" : 5, "tag" : "Go" }
    { "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }

    降序.sort({ _id:-1})

    > db.blogs.find({},{_id:0}).sort({_id:-1})
    { "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }
    { "title" : "Golang的指针", "rank" : 5, "tag" : "Go" }
    { "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" }
    { "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
    { "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" }
    { "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "Linux" }
    > 

    4.修改文档

    > db.blogs.update({"tag":"linux"},{$set:{"tag":"Linux"}});
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.blogs.find()
    { "_id" : ObjectId("601616c3a050f1d61c63303d"), "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "Linux" }
    { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" }
    { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
    { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" }
    { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" }
    { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }

    5.删除文档

    > db.blogs.remove({})
    WriteResult({ "nRemoved" : 11 })
    > db.blogs.count()
    0

    MongoDB高级查询

    我们在MySQL中常用的组合查询、分组聚合查询在MongoDB中基本都可以支持。

    1.根据json对象的key查询

    > db.blogs.find("tag":"Linux"); 
    2021-01-31T10:35:58.917+0800 E QUERY    [thread1] SyntaxError: missing ) after argument list @(shell):1:19
    > db.blogs.find({"tag":"Linux"});
    { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" }
    > 

    2.大于/小于/等于

    > db.blogs.find({"rank":{"$gte":4}});
    { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" }
    { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" }
    { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }
    > db.blogs.find({"rank":{"$gt":4}});
    { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" }
    { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }
    > db.blogs.find({"rank":{"$lte":4}});
    { "_id" : ObjectId("601616c3a050f1d61c63303d"), "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "linux" }
    { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" }
    { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
    { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" }
    > db.blogs.find({"rank":{"$lt":4}});
    { "_id" : ObjectId("601616c3a050f1d61c63303d"), "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "linux" }
    { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" }
    { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }

     3.模糊查询

    MongoDB的模糊查询支持正则表达式

    > db.blogs.find({"title":/n/});
    { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" }
    { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
    { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" }
    { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" }
    { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }
    > 

    查询title包含Python的文档

    > db.blogs.find({"title":/Python/});
    { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
    { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" }
    > 

    查询title以G开头的文档

    > db.blogs.find({"title":/^G/});
    { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" }
    { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }
    > 

    4.去重复

    > db.blogs.distinct("tag");
    [ "linux", "Linux", "Python", "Go", "Gin" ]
    > db.blogs.distinct("title");
    [
        "如何杀死僵尸进行",
        "Centos7设置服务开机自启动",
        "Python引用数据类型",
        "Python调用Golang",
        "Golang的指针",
        "Golang的web框架Gin"
    ]

    5.组合条件查询

    之前我们经常在根据用户输入 在前端组织1个搜索条件(json字典)然后传到后端,后端程序再处理json进行SQL拼接,发送给MySQL去执行。

    如果使用了MongoDB直接拿着前端传来的JSON数据进行查询即可。所以MongoDB很适合快速开发web应用。

    查询title中包含P 和 rank大于等于2的博客。(And)

    > db.blogs.find({title:/P/,rank:{$gte:2}});
    { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
    { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" }
    > 

    查询title包含O或者rank大于等于2的文档。(Or)

    > db.blogs.find({$or:[{title:/O/},{rank:{$gte:2}}]});
    { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" }
    { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
    { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" }
    { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" }
    { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }
    > 

    6.in查询

    > db.blogs.find({rank:{$in:[3,4]}});
    { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
    { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" }
    > 

    7.分组聚合查询

    根据tag进行分组,查询每个tag组的文章个数

    > db.blogs.aggregate([{"$group":{"_id":"$tag","数量":{"$sum":1}}}]);
    { "_id" : "Go", "数量" : 2 }
    { "_id" : "Gin", "数量" : 1 }
    { "_id" : "Python", "数量" : 1 }
    { "_id" : "Linux", "数量" : 2 }
    > 

    查看每个tag组rank的最小、最大、平均值

    > db.blogs.find()
    { "_id" : ObjectId("601616c3a050f1d61c63303d"), "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "Linux" }
    { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" }
    { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
    { "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" }
    { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" }
    { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }
    > db.blogs.aggregate([{"$group":{"_id":"$tag","平均分":{"$avg":"$rank"},"最大分":{"$max":"$rank"},"最小分":{"$min":"$rank"},"总分":{"$sum":"$rank"},"数量":{"$sum":1}}}])
    { "_id" : "Go", "平均分" : 4.5, "最大分" : 5, "最小分" : 4, "总分" : 9, "数量" : 2 }
    { "_id" : "Gin", "平均分" : 6, "最大分" : 6, "最小分" : 6, "总分" : 6, "数量" : 1 }
    { "_id" : "Python", "平均分" : 3, "最大分" : 3, "最小分" : 3, "总分" : 3, "数量" : 1 }
    { "_id" : "Linux", "平均分" : 1.5, "最大分" : 2, "最小分" : 1, "总分" : 3, "数量" : 2 }
    > 

    8.分页查询

    我们可以使用skip(0).limit(3).sort({_id:1})进行分页查询。

    //展示全部数据
    > db.blogs.find(); { "_id" : ObjectId("601616c3a050f1d61c63303d"), "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "Linux" } { "_id" : ObjectId("601616e4a050f1d61c63303e"), "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } { "_id" : ObjectId("601616fca050f1d61c63303f"), "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }
    {
    "_id" : ObjectId("6016170da050f1d61c633040"), "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } { "_id" : ObjectId("6016171da050f1d61c633041"), "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "_id" : ObjectId("6016172da050f1d61c633042"), "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }
     

      //总条目数为6

      > db.blogs.find().count();

      6

    //从0开始向后获取3条数据
    > db.blogs.find({},{_id:0}).skip(0).limit(3).sort({_id:1}); { "title" : "如何杀死僵尸进行", "rank" : 1, "tag" : "Linux" } { "title" : "Centos7设置服务开机自启动", "rank" : 2, "tag" : "Linux" } { "title" : "Python引用数据类型", "rank" : 3, "tag" : "Python" }

    //从3开始向后获取3条数据 > db.blogs.find({},{_id:0}).skip(3).limit(3).sort({_id:1}); { "title" : "Python调用Golang", "rank" : 4, "tag" : "Go" } { "title" : "Golang的指针", "rank" : 5, "tag" : "Go" } { "title" : "Golang的web框架Gin", "rank" : 6, "tag" : "Gin" }

    python操作MongoDB

    在日常开发中我们肯定会使用程序去操作数据库而并非命令行。在Python中我们可以使用pymongo模块。

    连接数据库 

    我们使用MySQL的前提是需要创建好数据库和用户然后进行授权。

    MongoDB只需要保证MongoDB服务运行正常即可。不需要手动创建数据库和授权。

    #Python操作MongoDB的API
    from pymongo import MongoClient
    # 创建连接
    conn = MongoClient("192.168.56.18", 27017)
    # 创建数据库对象(没有自动创建)
    db = conn.web
    # 创建集合对象(若没有自动创建)
    blog_set = db.blogs

    关闭数据连接

    我们在连接完MongoDB之后,最后一定要记得关闭数据连接。

    conn.close()

    插入数据

    # 插入数据到MongoDB
    # insert_one插入1个文档
    blog_set.insert_one({"title": "Linux启动过程", "rank": 18, "tag": "Linux"})
    # save插入1个文档:可以使用_id字段,对文档进行修改。
    blog_set.save(
        {"_id": 1, "title": "Linux一切皆文件思想2", "rank": 28, "tag": "Linux"}
    )
    # insert插入1个文档
    blog_set.insert({"title": "JavaScript从入门到放弃", "rank": 10, "tag": "JavaScript"})
    
    # 批量插入多个文档1
    blog_set.insert(
        [
            {"title": "JavaScript ES6语法", "rank": 18, "tag": "JavaScript"},
            {"title": "JavaScript原型", "rank": 10, "tag": "JavaScript"},
            {"title": "JavaScript闭包", "rank": 9, "tag": "JavaScript"},
        ]
    )
    # insert_many批量插入多个文档2
    blog_set.insert_many([
        {"title": "Golang的函数", "rank": 10, "tag": "Go"},
        {"title": "Golang面向接口编程", "rank": 5, "tag": "Go"},
        {"title": "Golang channel", "rank": 6, "tag": "Go"},
    ])

    操作游标

    pymongo调用find()查询方法之后会返回1个游标,我们对这个游标进行操作,可以获取到我们想要的数据。

    # 获取1个文档
    # print(cursor.next())
    # 跳过前2个文档
    cursor.skip(2)
    # 限制获取文档个数
    cursor.limit(2)
    # 文档复合排序
    cursor.sort([("_id", -1), ("rank", 1)])
    # 查看文档总条目
    print(cursor.count())

     

    find()查询操作

    find()返回1个游标对象,find()方法查询操作指令和在shell中的指令一致。

    # find()查询之后会返回1个游标
    cursor = blog_set.find({"rank": {"$gt": 9}}, {'_id': 0})
    # 查询所有
    for i in cursor:
        print(i)
        

    find_one()查询

    find_one()直接返回1个字典而不是游标对象。

    # 查询rank大于10 且tag=Linux的文档
    search_dict = {"$and": [{"rank": {"$gt": 10}}, {"tag": "Linux"}]}
    ret = blog_set.find_one(search_dict, {"_id": 0})
    print(ret)

    aggregate()分组聚合查询

    #聚合查询
    ret = blog_set.aggregate([{"$group": {"_id": "$tag", "数量": {"$sum": 1}}}])
    for i in ret:
        print(i)
    aggregate_search = [{"$group": {"_id": "$tag", "平均分": {"$avg": "$rank"}, "最大分": {"$max": "$rank"},
                                    "最小分": {"$min": "$rank"}, "总分": {"$sum": "$rank"}, "数量": {"$sum": 1}}}]
    ret = blog_set.aggregate(aggregate_search)
    for i in ret:
        print(i)
    conn.close()

    修改操作

    upsert=True在查询不到的情况下不去更新而是新增1条新数据

    multi=True可以控制修改的范围是所有

    # 1.给文档扩展1个域(key)
    blog_set.update({"title": "Linux一切皆文件思想2"}, {"$set": {"author": "张根"}})
    # 2.如果查询不到就新增一条记录:upsert=True来控制
    blog_set.update({"title": "Linux一切皆文件思想250"}, {"$set": {"author": "Tom"}}, upsert=True)
    # 3.multi=True修改多个文档
    blog_set.update({"title": "Linux一切皆文件思想250"}, {"$set": {"title": "Linux一切皆文件思想666"}}, multi=True)

    删除操作

    # 删除所有title=Linux一切皆文件思想666的文档
    blog_set.remove({"title": "Linux一切皆文件思想666"}, multi=True)

    参考

  • 相关阅读:
    朋友
    Music
    Rnadom Teams
    Bone Collector(01背包)
    Common Subsequence LCS
    Copying Books
    Equal Sum Sets
    Checker Challenge
    棋盘问题
    油田(Oil Deposits)
  • 原文地址:https://www.cnblogs.com/sss4/p/14349874.html
Copyright © 2020-2023  润新知