MongDB数据库

  • MongoDB的介绍

  

  MongoDB——一种非关系型数据库,是一个基于分布式文件存储的开源数据库系统。Mongodb 是目前最流行的 NoSQL 数据库之一,使用的数据类型 BSON(类似 JSON)。

  MongoDB相比较MySQL,MongoDB数据库更适合那些读作业较重的任务模型。MongoDB能充分利用机器的内存资源。如果机器的内存资源丰富的话,MongoDB的查询效率会快很多。总结为三点:一,易扩展。二,大数据量高性能。三,灵活的数据模型。

  • MongoDB的安装
  1. 从官网下载安装包

   下载地址:http://www.mongodb.org/downloads(注意有32位和64位之分)

    2.安装

除了第二步勾选‘i accept。。。’外,一直点Next就行了。

安装完成后查看bin文件夹,会看到些文件:

    3.启动MongoDB数据库

  安装完成后,在命令窗口输入mongo可以查看版本。

启动方式1: 启动: sudo service mongod start

     停止: sudo service mongod stop

     重启: sudo service mongod restart

     配置文件的位置:/etc/mongod.conf

     日志的位置:/var/log/mongodb/mongod.log

     默认端⼝:27017

启动方式2:

启动: sudo mongod [--dbpath=dbpath --logpath=logpath --append -fork] [–f logfile ] 。只以 sudo mongod 命令启动时,默认将数据存放在了 /data/db 目录下,需要手动创建

--dbpath: 指定数据库的存放路径

--logpath: 指定日志的存放路径

--logappend: 设置日志的写入形式为追加模式

-fork: 开启新的进程运行mongodb服务

f: 配置文件(可以将上述配置信息写入文件然后通过本参数进行加载启动) 

客户端mongo启动:

启动本地客户端:mongo

查看帮助:mongo –help

退出:exit或者ctrl+c

远程连接   命令: mongo xxx.xxx.xxx.xxx:27017/admin -uusername -p 输入password即可

  • MongoDB的权限管理

1.   为什么要进行权限管理的设置?

    刚安装完毕的mongodb默认不使用权限认证方式启动,与MySQL不同,mongodb在安装的时候并没有设置权限,然而公网运行系统需要设置权限以保证数据安全,所以我们要学习mongodb的权限管理。

2.    MongoDB的权限管理方案

  MongoDB是没有默认管理员账号,所以要先添加管理员账号,并且mongodb服务器需要在运行的时候开启验证模式 用户只能在用户所在数据库登录(创建用户的数据库),包括管理员账号。 管理员可以管理所有数据库,但是不能直接管理其他数据库,要先认证后才可以。

3.  MongoDB超级管理员账号的创建

  (3.1) 以权限认证的方式启动mongodb数据库

      sudo mongod -auth

      启动之后在启动信息中会有如下信息,说明mongodb以权限认证的方式启动成功

      [initandlisten] options: { security: { authorization: "enabled" } }

  (3.2)创建超级用户 使用admin数据库(超级管理员账号必须创建在该数据库上)

      use admin 创建超级用户

      db.createUser({"user":"python","pwd":"python","roles":["root"]})

      创建成功会显示如下信息:

      Successfully added user: { "user" : "python", "roles" : [ "root" ] }

  (3.3)退出客户端再次登录验证 此时再使用数据库各命令的时候会报权限错误,需要认证才能执行相应操作

      use admin

      db.auth('python','python')

      1

      python用户是创建在admin数据库上的所以必须来到admin数据库上进行认证,认证成功会返回1,失败返回0

  • MongoDB的基本操作

  1. mongodb数据库的命令

    查看当前的数据库:db(没有切换数据库的情况下默认使用test数据库)

    查看所有的数据库:show dbs /show databases

    切换数据库:use db_name

    删除当前的数据库:db.dropDatabase()

  2. mongodb集合的命令

    不手动创建集合: 向不存在的集合中第⼀次加⼊数据时, 集合会被创建出来

    手动创建结合: db.createCollection(name,options)

           db.createCollection("stu")

           db.createCollection("sub", { capped : true, size : 10,max:10 } )

           参数capped: 默认值为false表示不设置上限,值为true表示设置上限

           参数size: 当capped值为true时, 需要指定此参数, 表示上限⼤⼩,当⽂档达到上限时, 会将之前的数据覆盖, 单位为1KB=1024B

           max:条数

           查看集合:show collections

           删除集合:db.集合名称.drop()

           检查集合是否有上限: db.集合名.isCapped()

  3. mongodb中常见的数据类型

    Object ID: ⽂档ID

    String: 字符串, 最常⽤, 必须是有效的UTF-8

    Boolean: 存储⼀个布尔值, true或false

    Integer: 整数可以是32位或64位, 这取决于服务器

    Double: 存储浮点值

    Arrays: 数组或列表, 多个值存储到⼀个键

    Object: ⽤于嵌⼊式的⽂档, 即⼀个值为⼀个⽂档

    null: 存储null值

    Timestamp: 时间戳, 表示从1970-1-1到现在的总秒数123123123123

    Date: 存储当前⽇期或时间的UNIX时间格式

    >Date() :当前时间

    >ISODate("2016-01-24T12:52:33.341Z").valueOf() :时间戳(毫秒)

    注意点:

      每个⽂档都有⼀个属性, 为_id, 保证每个⽂档的唯⼀性,mongodb默认使用_id作为主键

       可以⾃⼰去设置_id插⼊⽂档,如果没有提供, 那么MongoDB为每个⽂档提供了⼀个独特的_id, 类型为objectID

      objectID是⼀个12字节的⼗六进制数,每个字节两位,一共是24 位的字符串: 前4个字节为当前时间戳 接下来3个字节的机器ID 接下来的2个字节中MongoDB的服务进程id 最后3个字节是简单的增量值。

  • MongoDB的增删改查
  1.           db.collection_name.insert({"_id":"111"})
      _id如果已经存在,insert方法会报错,不存在的时候,会插入新数据
 
  1.   db.collection_name.save({"_id":"111","name":"bob","age":"18"})
      _id如果存在,会更ddvd cx x新其他键对应的值(name,age),不存在的时候,会新插入数据
  1.    db.collection_name.remove({条件},{justOne:true})
      默认情况下,会删除全部满足条件的内容,justOne:true时值删一条
 
  1.    db.collections_name.drop()
      删除整个集合(collections_name)
 
  1.   db.collections_name.update({name:"bon"},{name:"fan"})
      更新 将名字为”bon”改为”fan” 弊端:会将collections_name内容代替  如:  db.text01.find() 
      { "_id" : "3", "name" : "fan", "age" : "16" } 
      db.text01.update({name:"fan"},{name:"xlnx"}) 
      { "_id" : "3", "name" : "xlnx" } 
 
  2.   db.collections_name.update({nmae:"bob"},{$set:{name:"fan"}})
      只能修改一条数据,并不会代替,将bob修改为fan
 
  3.   db.collection_name.update({条件},{$set:{name:jack}},{multi:true})
      在原有数据下,如果存在指定想修改的那个个条件,那就修改,如果不存在,就增加这一条数据。如果为False,就不执行
      默认情况下会修改一条,multi:true时可以修改满足条件的全部数据
 
      注意:multi update only works with $ operatorsmulti:true 只能跟$set连用

  1.⽅法  find(): 查询

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

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

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

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

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

    db.collection_name.find({"age":16})       查询年龄为16
    db.collections_name.findOne()       查询只返回第一个
    db.collections_name.find().pretty()    将查询结果格式化
 
 
  • 比较运算符
    等于 默认就是等于判断,没有运算符
    大于 $gt        db.collection_name.find({age:{$gt:18}}) 查询年龄大于18
    大于等于$gte    db.collection_name.find({age:{$gte:18}})
    小于 $lt         db.collections_name.find({age:{$lt:18}})查询年龄小于18
    小于等于$lte    db.collection_name.find({age:{$lte:18}})
    不等于 $ne      db.collection_name.find({age:{$ne:18}})
 
    db.student.find({'price':{$lte:6000,$gt:500},'color':'bule'})  小于等于6000大于500并且颜色为蓝色
 
  • 逻辑运算符
    and 
    在JSON中写多个条件即可:查询年龄大于或等于18, 并且性别为true的学生
    db.collections_name.find({age:{$gte:18}},gender:"true"})
    or $or 
    使用$or 值为数组,数组中每个元素为json:查询年龄大于18, 或性别为false的学生
    db.collection_name.find({$or:[{age:{$gte:18}},{gender:true}]})
    形式 db.collection_name.find({$or:[{条件1},{条件2},{条件3}.....]})
  • 范围运算符
    ”in","in","nin” 判断是否在某个范围内
        查询年龄为18、 28
        db.collection_name.find({age:{$in:[18,28]}})
    $nin     不在范围内
        db.collections_name.find({age:{$gt:{$in:[25,16]}}})
 
  • 支持正则表达式(两种方式)
    使用 /xxx/ 
        db.collection_name.find({sku:/^a/}) 查找sku字段中以a开头的
        db.collections_name.find({sku:/9$/})查找sku字段中以9结尾的
    $regex     编写正则 值必须时字符串 
        db.collection_name.find({sku:{$regex:"^a"}})查找sku字段中以a开头的
        db.collections_name.find({sku:{$regex:"9$""}})查找sku字段中以9结尾的
 
  • limt        skip
   方法  limit()用于读取指定数量的文档
    db.集合名称.find().limit(NUMBER) 
    db.collection_name.find().limit(2)取两条
   方法  skip()用于跳过指定数量的文档
    db.集合名称.find().skip(NUMBER) 
    db.collection_name.find().skip(2)跳过两条
  连用 
    db.collection_name.find().limit(2).skip(2)先取两页再跳过2条
    db.collections_name.find().skip(2).limi(2)先跳两页,再取2条 —–比较高效常用
 
  • sort排序
    db.collections_name.find({}).sort({name:1,gender:-1})
      1为升序,-1为降序
  • 统计 count
    db.collections_name.find().count()
    db.collections_name.count({gender:true})  统计geder:true的个数
  • 去重distinct
    db.collections_name.distinct("去重字段",{条件})
    例:
    db.collections_name.distinct("hometown",{gneder:true,age:{$gt:18}}) 
    给hometown字段去重,并且gender为true ,age大于18的
    返回的是一个列表
 
  • MongDB的聚合操作

    聚合(aggregate):是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。

       db.collections_name.aggregate(管道:{表达式})

常用管道命令
 
      $group        将文档分组,可用于统计结果
      $match        过滤数据,输出符合条件的文档
      $project        修改输入文档的结构,如:重命名,增加,删除字段,创建统计结果(就是把计算完的结果输出)
      $sort             将文档排序后,输出
      $limt             限制聚合管道返回的档数,取几条
      $skip        跳过指定数量的文档, 并返回余下的文档
      $unwind        将数组类型的字段进行拆分
表达式
处理输出文档并输出
语法:表达式:'$列名' {$..:{}}
 
常用表达式:
      $sum:计算总和,sum:计算总和,sum:1 表示以1倍计数 表示把每一条数据当作1来计算
      $avg: 计算平均值
      $min: 获取最小值
      $max: 获取最大值
      $push: 在结果文档中插入值到一个数组中  插入的值必须是中括号
      $first: 根据资源文档的排序获取第1个文档数据
      $last: 根据资源wenwen档的排序获取最后1个文档数据
动手
将⽂档中的某⼀个数组类型字段拆分成多条, 每条包含数组中的⼀个值 
      语法:db.集合名称.aggregate({unwind:′unwind:′字段名称’})
投影
返回特定的字段
      db.collection_name.find({条件},{name:1,_id:0})
      _id 不需要显示的时候,值为0,其他字段不需要的时候,不写即可显示时值为1
      db.collections_name.find({条件},{name:1,_id:0}) 显示name 不显示其他字段,不需要id时就爱那个id设为0
统计个数
      db.collection_name.find({条件}).count()
      db.collection_name.count({条件})
去重
      db.stu.distinct(“hometown”,{gender:true,age:{$gt:18}})
      返回数组
 
  • 索引操作

1.为什么mongdb需要创建索引?

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

2.mongodb创建简单的索引方法 :

注意:从 mongoDB 3.0 开始,ensureIndex 被废弃,今后都仅仅是 createIndex 的一个别名。

      db.p2p.opinion.createIndex({'author':1});    创建
      db.p2p.opinion.getIndexes();    查看
      db.p2p.opinion.dropIndex({'author':1});    删除
 
创键索引 
      db.colllectons_name.ensureIndex({属性:1})
      语法:db.集合.ensureIndex({属性:1})  1表示升序, -1表示降序具体操作:`db.t1.ensureIndex({name:1})
      db.collection_name.creatreIndex({属性:1}).explain('executionStats')explain(‘executionStats’)   查看查询的时间
创建唯一索引 
      db.collections_name.createindex({name:1},{"unique":true})
      db.集合.creteindex({属性:1})       1表示升序,-1表示降序
创建联合索引——去重一般用三个字段 
      db.collection_name.ensureindex({name:1,age:1})
查看索引 
      db.collection_name.getindexes()
删除索引 
      db.collection_name.dropindex()
数据去重
数据库建立索引,需要建立联合索引,通过数据库来实现数据的自动去重。
根据url地址去重,把url地址存在redis的集合中,后续新来一个url地址,判断他是否存在redis中,不存在才抓取。 
url对应的响应不会变化的时候,使用sha1加密数据(可以选择加密某些字段),把得到的结果存入redis的集合中,后续新抓到的数据同样的方式进行加密,判断得到的值在redis的集合中是否存在,存在就更新,不存在就插入。

3. 创建索引前后查询速度对比

测试:

插入10万条数据到数据库中 插入数据:   for(i=0;i<100000;i++){db.t1.insert({name:'test'+i,age:i})}

创建索引前:     db.t1.find({name:'test10000'}) db.t1.find({name:'test10000'}).explain('executionStats')

创建索引后:     db.t255.ensureIndex({name:1}) db.t1.find({name:'test10000'}).explain('executionStats')

前后速度对比:

  • 数据库的备份恢复与导出导入
 
数据库的备份        mongodump -h hostname -d db -o path
数据库的恢复        mongorestore -h hostname -d db -dri path
导出         mongoexport -u -p --authorization
导入         mongoimport -u -p --authorization
          -h: 服务器地址
          -d: 数据库名
           -c: 集合名
           -o: 导出文件名 
          --type: 文件类型,默认json格式,可选数据类型json,csv -f: 需要导出的字段,导出为json格式的数据时可以不指定导出哪些字段,默认全部,导出成csv文件是必须指定
 
  • mongo和python交互

1. mongdb和python交互的模块

  pymongo 提供了mongdb和python交互的所有方法 安装方式: pip install pymongo

from pymongo import MongoClient


class MongoUtil(object):

    def __init__(self,host,port,db):
        self.conn = MongoClient(host=host,port=port)
        self.db = self.conn[db]

    def get_state(self):
        return True

    def auth(self,name,password,source):
        '''
        登录
        :param name:用户名
        :param password:密码
        :param source:授权数据库
        :return: true/false
        '''
        if self.get_state():
            try:
                return self.db.authenticate(name=name,password=password,source=source)
            except:
                return False
        else:
            return False

    def insert_one(self,collection,document):
        '''
        插入单条
        :param collection: 集合名
        :param document: 文档(单条),类型:dict
        :return: 插入的这条数据的ID
        '''
        if self.get_state():
            result = self.db[collection].insert_one(document=document)
            return result.inserted_id
        else:
            return ''

    def insert_many(self,collection,documents):
        '''

        :param collection: 集合名
        :param documents: 文档(多条),类型:list(dict)
        :return: 受影响的ID
        '''
        if self.get_state():
            result = self.db[collection].insert_many(documents=documents)
            return result.inserted_ids
        else:
            return ''

    def update_one(self,collection,filter,update,upsert=False):
        '''

        :param collection:
        :param filter:
        :param update:dict
        :param upsert:
        :return:修改后的结果
        '''
        if self.get_state():
            return self.db[collection].update_one(filter=filter,update=update,upsert=upsert)
        else:
            return None

    def update_many(self,collection,filter,update,upsert=False):
        '''

        :param collection:
        :param filter:
        :param update:list(dict)
        :param upsert:
        :return:修改后的结果
        '''
        if self.get_state():
            return  self.db[collection].update_many(filter=filter,update=update,upsert=upsert)
        else:
            return None

    def find(self,collection,filter=None,column=None):
        '''

        :param collection:集合名
        :param filter:过滤器
        :param column:投影
        :return:结果集
        '''
        if self.get_state():
            result = self.db[collection].find(filter,column)
            return result
        else:
            return None

    def  delete_one(self,collection,filter):
        '''
        :param collection:
        :param filter:
        :return:删除的条数
        '''
        if self.get_state():
            return self.db[collection].delete_one(filter=filter)
        else:
            return 0

    def  delete_many(self,collection,filter):
        '''
        :param collection:
        :param filter:
        :return:删除的条数
        '''
        if self.get_state():
            return self.db[collection].delete_many(filter=filter)
        else:
            return 0

    def aggregate(self,collection,pipline):
        '''

        :param collection:
        :param pipline: 管道(如果多个阶段,需要list,例如:[{'$group':...},{'$match':...}])
        :return:
        '''
        if self.get_state():
            result = self.db[collection].aggregate(pipeline=pipline)
            return result
        else:
            return None

    def close(self):
        self.conn.close()



if __name__ == '__main__':
    # 链接mongo
    mongo = MongoUtil(host='192.168.1.29',port=27017,db='python')
    # 授权
    result = mongo.auth(name='liumingyi',password='123456',source='admin')
    if result:
        # 操作:单条插入
        insertID = mongo.insert_one(collection='car',document={'car':'奥拓','price':3000})
        #输出刚才插入的数据
        result = mongo.find(collection='car',filter={'_id':insertID})
        for i in result:
            print(i)
        # 更新
        # result = mongo.update_one(collection='car',filter={'name':'奥拓5'},update={'$set':{'price':5000}},upsert=True)
        # print(result)
        # result = mongo.update_many(collection='car', filter={'car': '奥拓'}, update={'$set': {'price': 5000}})
        # print(result)

        # 删除
        result = mongo.delete(xxx)

    else:
        print('授权失败')

2 .使用pymongo如果理解麻烦的话,那再来个简化版的:

from pymongo import MongoClient

#1.连接mongo
con = MongoClient(host='localhost',port=27017)
#2.连接数据库
db = con['python']
#3.授权
db.authenticate(name='wangrui',password='123456',source='admin')
#4.连接集合
coll = db['car']
#5.查找操作
result = coll.find({'carname':'宝马'},{'_id':0,'carname':1,'price':1})
for i in result:
    print(i)

#6.更新
result = coll.update_one({'carname':'宝马'},{'$set':{'carname':'玛莎拉蒂'}})
print(result)

#7.增加
result = coll.insert_one({'carname':'兰博基尼','price':40000})

#8.删除
result = coll.delete_one({'carname':'兰博基尼'})
print(result)

#9.聚合
result = coll.aggregate([{'$group':{'_id':'$carname','count':{'$sum':1}}}])
for i in result:
    print(i)

好了,结束,祝大家天天愉快!^_^

原文地址:https://www.cnblogs.com/onerose/p/10241512.html