zoukankan      html  css  js  c++  java
  • MongoDB数据库

    一.MongoDB

    1.爬虫的数据存储
        可以放到mysql ,mysql 是关系型数据库 ,是基于硬盘存储的
        当并发量太大时,mysql 可能无法支撑, 需要将数据库设计为分布式
        mysql当然也支持分布式,但是分布式不是mysql的强项
    
        反观MongoDB,它从一开始设计时就是奔着分布式去的,只需要简单的配置就能实现高效的分布式存储
        被大量应用于大数据领域
    
    2.MongoDB是一款基于C++编写的分布式非关系型数据库    noSQL:Not only SQL
    
    3.Mongodb与redis数据库的区别
        MongoDB是最像关系型数据库的非关系型数据库,更加适用于大数据.
        redis则更加倾向于较小的数据,但性能更高一点
    
    4.为什么爬虫需要使用MongoDB?
        因为一些爬虫程序要爬取的数据非常多,简单的储存系统已经无法满足需求了     

    二.MongoDB安装

    如果报错2502或2503 
    1、以管理员身份运行cmd命令 (Win + X, A)
    2.在该安装包所正的目录下输入:msiexec /package + 安装包名  进行安装
    
    安装过程中出现
    出现service MongoDB failed to start,verify that you have sufficient privileges to start system services 错误
    
    删除bin文件夹中mongod.cfg文件下#snmp: 后面的内容 
    然后进入services.msc找到MongoDB Server,右键属性登录选择本地系统登录,然后Retry 即可
    
    此时MongoDB已经开启,浏览器访问http://localhost:27017/,页面上输出:
    It looks like you are trying to access MongoDB over HTTP on the native driver port.
    说明MongoDB已经启动了,且它的默认端口(27017)没有被占用。

    三.重要概念

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

    四.使用

    将bin文件夹加入环境变量
    在cmd    下输入mongo,看见欢迎信息说明登录成功
    此时没有任何的权限限制,默认是管理员角色

    1.创建账号

    #1、创建账号
    use admin 
    db.createUser(
      {
        user: "root",
        pwd: "123",
        roles: [ { role: "root", db: "admin" } ]  #角色:root是管理员角色,对admin有操作权限
      }
    )
    
    use test1
    db.createUser(
      {
        user: "henry",
        pwd: "123",
        roles: [ { role: "readWrite", db: "test1" },  #readwrite是可读可写角色
                 { role: "read", db: "test2" } ]      #read是只读角色
      }
    )
    
    key都是固定的不能随便写,每一个key都有特殊含义
    在mongodb中用不同的数据库来区分权限,创建管理员账户在admin下创建!
    db 是一个全局变量 表示当前数据库
    db.createUser()是调用一个内部函数用于创建用户
    每个账号可以具备多个角色
    
    注意:创建管理员账户在admin下创建.
        往其他数据创建用户,需要在admin登录状态下,进入该数据库进行创建
        admin可以操作库,集合,文档的增删改查
        如果使用其他数据库登录,只能按照自己规定的数据库的角色进行操作

    2.开启账户认证

    为了安全我们需要在配置文件中设置密码
    1.配置文件 bin下的mongod.cfg文档
    2.找到文档中的#security:  (用来进行安全配置)
    security:
        authorization: enabled
    # 注意缩进
    重启MongoDB Server服务,启用认证!

    账号检测

    #直接mongo进入程序  已经无法查看数据库
    show dbs 
    
    #登录方式1:  authenticationDatabase指定数据库
    mongo --port 27017 -u "root" -p "123" --authenticationDatabase "admin"
    
    #登录方式2:
    进入mongo后
    use admin
    db.auth("root","123")
    #1 表示登陆成功
    
    进入mongo后
    use test1
    db.auth("henry","123")
    
    #删除账号 注意:只有在admin下登录进入用户注册的数据库才能删除用户账号
    db.dropUser('用户名');
    
    #修改密码
    db.changeUserPassword(用户名, 新密码);
    
    #查看帮助信息
    db.help

    五.Mongodb操作

    1.库的操作

    #创建数据库:
    use 数据库名称
    #如果有则切换没有则创建新的
    
    # 查看数据库:
    show dbs
    #注意show dbs 有数据的库显示没有数据的库不显示
    
    #删除
    db.dropDatabase()
    #注意区分大小写

    2.集合的操作

    集合是一个存储数据元素的容器类比mysql中的表

    进入指定数据库
    #创建集合:
    db.user
    
    #查看集合:
    show collections
    show tables
    # 同样的数据集合中没有数据则 不会显示
    
    #以下数据之间没有任何关系仅仅是名字有相同部分 数据之间的关系需要应用程序维护
    db.blog
    db.blog.user  #(建立了一个叫blog.user的集合)
    db.blog.common
    
    #删除集合:如果集合中没有文档,删除的话会返回false,有文档删除才是true
    db.blog.user.drop()
    db.user.drop()

    3.记录的(文档)操作

    插入数据

    #1、没有指定_id 则会默认生成_id值为ObjectId,_id不能重复,且在插入后不可变.
    #MngoDB的语法就是js的语法 所以 json支持的数据类型 MongoDB都支持
    
    #2、插入单条
    user={
        "name":"egon",
        "age":10,
        'hobbies':['music','read','dancing'],
        'addr':{
            'country':'China',
            'city':'BJ'
        }
    }
    
    db.test.insert(user)
    
    # 如果id已经存在则覆盖,否则插入
    db.test.save({"_id":10,"name":"henry"})
    
    
    #3、插入多条
    user1={
        "_id":1,
        "name":"alex",
        "age":10,
        'hobbies':['music','read','dancing'],
        'addr':{
            'country':'China',
            'city':'weifang'
        }
    }
    
    user2={
        "_id":2,
        "name":"wupeiqi",
        "age":20,
        'hobbies':['music','read','run'],
        'addr':{
            'country':'China',
            'city':'hebei'
        }
    }
    
    
    user3={
        "_id":3,
        "name":"yuanhao",
        "age":30,
        'hobbies':['music','drink'],
        'addr':{
            'country':'China',
            'city':'heibei'
        }
    }
    
    user4={
        "_id":4,
        "name":"jingliyang",
        "age":40,
        'hobbies':['music','read','dancing','tea'],
        'addr':{
            'country':'China',
            'city':'BJ'
        }
    }
    
    user5={
        "_id":5,
        "name":"jinxin",
        "age":50,
        'hobbies':['music','read',],
        'addr':{
            'country':'China',
            'city':'henan'
        }
    }
    db.user.insertMany([user1,user2,user3,user4,user5])

    查询数据

    find 查找所有匹配数据
    findOne 查找第一个匹配的
    db.user.find().pretty()  # 格式化查询结果
    
    =============================比较运算=============================
    # SQL:=,!=,>,<,>=,<=
    # MongoDB:{key:value}代表什么等于什么,"$ne","$gt","$lt","gte","lte",其中"$ne"能用于所有数据类型
    
    #1、select * from db1.user where name = "cxx";
    db.user.find({'name':'cxx'})
    
    #2、select * from db1.user where name != "cxx";
    db.user.find({'name':{"$ne":'cxx'}})
    
    #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 = "cxx";
    db.user.find({
        "$or":[
            {'_id':{"$gte":5}},
            {"name":"cxx"}
            ]
    })
    
    #4、select * from db1.user where id % 2=1;
    #id为奇数的数据
    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']}})
    
    
    =============================查询指定字段=============================
    db.user.find({'_id':3},{'_id':0,'name':1,'age':1})
    #{ "name" : "yuanhao", "age" : 30 }
    
    db.user.find({'_id':3},{'name':1,'age':1})
    #{ "_id" : 3, "name" : "yuanhao", "age" : 30 }
    0表示不显示,1为显示 id默认为1 其余字段默认为0
    
    
    =============================正则匹配=============================
    # SQL: regexp 正则
    # MongoDB: /正则表达/i    i忽略大小写
    
    #1、select * from db1.user where name regexp '^j.*?(g|n)$';
    db.user.find({'name':/^j.*?(g|n)$/i})
    
    
    =============================查询数组=============================
    #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、查看所有人最后两个爱好
    db.user.find({},{'hobbies':{"$slice":-2},"age":0,"_id":0,"name":0,"addr":0})
    
    #5、查看所有人的第2个到第3个爱好  {"$slice":[1,2]}从索引1开始取两个值
    db.user.find({},{'hobbies':{"$slice":[1,2]},"age":0,"_id":0,"name":0,"addr":0})
    
    ===============================其他===============================
    # 排序:1代表升序,-1代表降序
    db.user.find().sort({"name":1,})
    db.user.find().sort({"age":-1,'_id':1}) 
    db.user.find().sort({"_id":1,'age':-1}) 
    #先以第一个key为依据排列,第一个相同再按照第二个排列
    
    
    # 分页: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({})
    
    #3、查找一个,与find用法一致,只是只取匹配成功的第一个
    db.user.findOne({"_id":{"$gt":3}})

    修改数据

    ======================================update==========================================
    
    update() 方法用于更新已存在的文档。语法格式如下:
    db.collection.update(
       <query>,
       <update>,
       {
         upsert: <boolean>,
         multi: <boolean>,
         writeConcern: <document>
       }
    )
    参数说明:对比update db1.t1 set name='EGON',sex='Male' where name='egon' and age=18;
    
    query : 相当于where条件。
    update : update的对象和一些更新的操作符(如$,$inc...等,相当于set后面的
    upsert : 可选,默认为false,代表如果不存在update的记录不更新也不插入,设置为true代表插入。
    multi : 可选,默认为false,代表只更新找到的第一条记录,设为true,代表更新找到的全部记录。
    writeConcern :可选,抛出异常的级别。
    
    更新操作是不可分割的:若两个更新同时发送,先到达服务器的先执行,然后执行另外一个,不会破坏文档。
    
    
    =========================================覆盖式=========================================
    #注意:除非是删除,否则_id是始终不会变的
    #覆盖式:
    db.user.update({'age':20},{"name":"Wxx","hobbies_count":3})
    是用{"_id":2,"name":"Wxx","hobbies_count":3}覆盖原来的记录
    
    
    
    =====================================设置:$set=========================================
    
    通常文档只会有一部分需要更新。可以使用原子性的更新修改器,指定对文档中的某些字段进行更新。
    更新修改器是种特殊的键,用来指定复杂的更新操作,比如修改、增加后者删除
    
    #1、update db1.user set  name="WXX" where id = 2
    db.user.update({'_id':2},{"$set":{"name":"WXX"}})
    
    #2、没有匹配成功则新增一条{"upsert":true}
    db.user.update({'_id':6},{"$set":{"name":"egon","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、修改内嵌文档,把名字为alex的人所在的地址国家改成Japan
    db.user.update({'name':"alex"},{"$set":{"addr.country":"Japan"}})
    
    #5、把名字为alex的人的地2个爱好改成piao
    db.user.update({'name':"alex"},{"$set":{"hobbies.1":"piao"}})
    
    #6、删除alex的爱好,$unset
    db.user.update({'name':"alex"},{"$unset":{"hobbies":""}})
    
    
    
    =============================增加和减少$inc=====================================
    #1、所有人年龄增加一岁
    db.user.update({},
        {
            "$inc":{"age":1}
        },
        {
            "multi":true
        }
        )
    #2、所有人年龄减少5岁
    db.user.update({},
        {
            "$inc":{"age":-5}
        },
        {
            "multi":true
        }
        )
    ===============================添加删除数组元素==================================
    往数组内添加元素:$push
    #1、为名字为yuanhao的人添加一个爱好read
    db.user.update({"name":"yuanhao"},{"$push":{"hobbies":"read"}})
    
    #2、为名字为yuanhao的人一次添加多个爱好tea,dancing
    db.user.update({"name":"yuanhao"},{"$push":{
        "hobbies":{"$each":["tea","dancing"]}
    }})
    
    按照位置且只能从开头或结尾删除元素:$pop
    #3、{"$pop":{"key":1}} 从数组末尾删除一个元素
    
    db.user.update({"name":"yuanhao"},{"$pop":{
        "hobbies":1}
    })
    
    #4、{"$pop":{"key":-1}} 从头部删除
    db.user.update({"name":"yuanhao"},{"$pop":{
        "hobbies":-1}
    })
    
    #5、按照条件删除元素,:"$pull" 把符合条件的统统删掉,而$pop只能从两端删
    db.user.update({'addr.country':"China"},{"$pull":{
        "hobbies":"read"}
    },
    {
        "multi":true
    }
    )
    
    
    =====================================避免添加重复:$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 把之前的值全部删掉 再切割出指定的数据 加入列表
    #注意:不能只将"$slice"或者"$sort"与"$push"配合使用,且必须使用"$each"

    删除数据

    #1、删除多个中的第一个
    db.user.deleteOne({ 'age': 8 })
    
    #2、删除国家为China的全部
    db.user.deleteMany( {'addr.country': 'China'} ) 
    
    #3、删除全部
    db.user.deleteMany({})

    六.可视化

    安装:Robo 3T

    七.pymongo

    from pymongo import MongoClient
    
    #1、链接
    client=MongoClient('mongodb://root:123@localhost:27017/')
    
    # client = MongoClient('localhost', 27017)
    # db = client["admin"]
    # db.authenticate("root","123")
    
    #2、use 数据库
    db=client['db1']  #等同于:client.db1
    
    #3、查看库下所有的集合
    print(db.collection_names(include_system_collections=False))
    
    #4、创建集合
    table_user = db['user'] #等同于:db.user
    
    #5、插入文档
    table_user.insert({"_id":30,"name":"wade"})
    
    #6、查找
    print(table_user.find_one())
    
    for item in table_user.find():
        print(item)
    
    print(table_user.find_one({"_id":{"$gte":1},"name":'egon'}))
    
    #7、更新
    table_user.update({'_id':1},{"$set":{'name':'EGON'}})
    
    #8、传入新的文档替换旧的文档
    table_user.save(
        {
            "_id":2,
            "name":'egon_xxx'
        }
    )
    
    #9.删除数据
    table_user.delete_one({"name":"wade"})

    八.分组聚合

    #插入一组数据
    from pymongo import MongoClient
    import datetime
    
    client=MongoClient('mongodb://root:123@localhost:27017')
    table=client['db1']['emp']
    
    l=[
    ('张飞','male',18,'20170301','teacher',7300.33,401,1), #以下是教学部
    ('张云','male',78,'20150302','teacher',1000000.31,401,1),
    ('刘备','male',81,'20130305','teacher',8300,401,1),
    ('关羽','male',73,'20140701','teacher',3500,401,1),
    ('曹操','male',28,'20121101','teacher',2100,401,1),
    ('诸葛亮','female',18,'20110211','teacher',9000,401,1),
    ('周瑜','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)
        

    案例:爬取京东并将数据存入mongoDB

    #爬取数据
    from selenium.webdriver import Chrome
    from urllib.parse import urlencode
    import time
    from MongoDB.爬取京东 import DBTool
    
    driver = Chrome()
    #https://search.jd.com/Search?keyword=%E6%9D%9C%E8%95%BE%E6%96%AF&enc=utf-8&wq=%E6%9D%9C%E8%95%BE%E6%96%AF&page=3
    
    #使用 urlencode 传入指点key-value字典形式,返回值可以直接完成路径拼接
    kw = input("搜索:").strip()
    num = int(input("要获取几页数据:").strip())
    
    def get_all_datas(i,kw):
        par = {"keyword":kw,"enc":"utf-8","wq":kw,"page":i}
        kw = urlencode(par)
        url = "https://search.jd.com/Search?" + kw
        driver.get(url)
    
        #隐式等待
        driver.implicitly_wait(10)
    
        #执行js代码获取页面总高度
        height = driver.execute_script("return document.body.clientHeight")
    
        #执行js代码滑动页面.完成页面的加载
        driver.execute_script("""
            window.scrollTo({
                top : %s,
                behavior:"smooth"
            });""" % height)
    
        #获取商品列表
        def get_items():
            #获取包裹商品的大标签
            ul = driver.find_element_by_class_name("gl-warp")
    
            #获取商品列表
            items = ul.find_elements_by_class_name("gl-item")
            #判断数据是否全部加载完毕
            if len(items) == 60:
                return items
    
            #没有加载完毕回调函数,直到该页面的数据全部加载完毕
            return get_items()
    
        #调用获取函数获取数据
        items = get_items()
    
        #解析商品列表.得到所需数据
        for i in items:
            link = i.find_element_by_css_selector(".p-img a").get_attribute("href")
            img = i.find_element_by_css_selector(".p-img a img").get_attribute("src")
            if not img:
                img = i.find_element_by_css_selector(".p-img a img").get_attribute("data-lazy-img")
                img = "https:" + img
            price = i.find_element_by_css_selector(".p-price i").text
            title = i.find_element_by_css_selector(".p-name a em").text
            shop_name = i.find_element_by_css_selector(".p-shop a").text
            commit = i.find_element_by_css_selector(".p-commit strong").text
            dic = {"link":link,"img":img,"price":price,"title":title,"shop_name":shop_name,"commit":commit}
            #将数据存放到MongoDB中去
            DBTool.insert_data(dic)
    
    
    for i in range(num):
        i = 2*i+1
        get_all_datas(i,kw)
    
    time.sleep(30)
    #关闭浏览器
    driver.close()
    #关闭mongoDB数据库连接
    DBTool.close()
    
    
    
    #DBTool
    """
    连接数据库 保存数据
    """
    from pymongo import MongoClient
    table = None
    c = None
    
    #连接服务
    def connect_service():
        global table,c
        c = MongoClient("mongodb://root:123@127.0.0.1:27017")
        table = c["jd"]["jd_data"]
    
    #插入数据
    def insert_data(data):
        if not table:
            connect_service()
        table.insert(data)
    
    #关闭连接
    def close():
        c.close()
  • 相关阅读:
    内存之RAM、SRAM、DRAM、ROM、FLASH、SDRAM、DDR*
    音频接口之AUX、TRS、RCA、SLR、AES/EBU、S/PDIF
    视频接口之AV、S端子、VGA、DVI、HDMI、DP
    选购硬盘HDD、SSD、SSHD、IDE、SATA、SCSI、SAS、PCIe、M.2、USB
    浅析C#中的“==”和Equals
    编写更好的C#代码
    C# 文件下载四方法
    Linq之Lambda表达式初步认识
    .NET逻辑分层架构总结
    理解 .NET 2015
  • 原文地址:https://www.cnblogs.com/lizeqian1994/p/10751292.html
Copyright © 2011-2022 走看看