MongoDB及在Python下的使用

MongoDB

1. 简介

  • MongoDB是一个基于 分布式 文件存储 的 NoSQL数据库
  • 由C++语言编写,运行稳定,性能高
  • 旨在为Web提供可扩展的高性能存储解决方案

名词

SQL术语/概念 MongoDB术语/概念 解释/说明
database database 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
table joins   表连接,MongoDB不支持
primary key primary key 主键,MongoDB自动将_id字段设置为主键
  • 三元素: 数据库,集合,文档

    • 集合就是关系数据库中的表
    • 文档对应着关系数据库中的行
  • 文档,就是一个对象,由键值对构成,是Json的扩展Bson形式

  • 集合: 类似于关系数据库中的表,存储多个文档,结构不固定,如可以存储如下文档在一个集合中

    {
          
          "name":"guojing","gender":"男"}
    {
          
          "name":"huangrong","age":18}
    {
          
          "book":"shuihuzhuan","heros":"108"}
    
  • 数据库: 是一个集合的物理容器,一个数据库中可以包含多个文档

  • 一个服务器通常有多个数据库

2. 基本操作

2.1 安装

下载mongodb,注意两点

  1. 根据业界规则,偶数为稳定版,奇数为开发板
  2. 32位的mongodb最大只能存放2G数据(默认是已经不提供32位的了)

启动服务端

安装完成后,进入到mongodb的安装路径,使用mongod命令来启动服务端:

有一条错误信息,意思是没有找到指定的目录,这是mongodb的数据存储路径

安装MongoDB服务

配置MongoDB服务

管理员模式打开命令行窗口
创建目录,执行下面的语句来创建数据库和日志文件的目录

mkdir c:\data\db
mkdir c:\data\log

创建配置文件
创建一个配置文件。该文件必须设置 systemLog.path 参数,包括一些附加的配置选项更好。

例如,创建一个配置文件位于 C:\data\mongod.cfg,其中指定 systemLog.path 和 storage.dbPath。具体配置内容如下:

扫描二维码关注公众号,回复: 12903946 查看本文章
systemLog:
    destination: file
    path: c:\data\log\mongod.log
storage:
    dbPath: c:\data\db
安装MongoDB服务

通过执行mongod.exe,使用--install选项来安装服务

mongod --config c:\data\mongo.cfg --install --serviceName MongoDB

启动MongoDB服务

net start MongoDB
连接MongoDB服务
mongo

或者使用MongoDB的GUI工具,在安装MongoDB的时候回一并安装

2.2 数据库操作

数据库切换

  • 查看当前数据库名称 : db
  • 查看所有数据库名称/列出所有在物理上存在的数据库 : show dbs
  • 切换数据库 : use 数据库名称
    • 如果数据库不存在,则指向数据库,但不创建,直到插入数据或创建集合时数据库才被创建
  • 默认的数据库为test,如果没有创建新的数据库,集合将存放在test数据库中

数据库删除

db.dropDatabase()
  • 会删除当前指向的数据库
  • 如果数据库不存在,则什么也不做

2.3 集合操作

创建集合

语法:

db.createCollection(name, options)
  • name是要创建的集合的名称
  • options是一个文档,用于指定集合的配置
  • 选项参数是可选的,所以只要指定集合名称

例1:
不限制集合的大小

db.createCollection("stu")

例2:
限制集合大小

db.createCollection("sub", {capped : true, size : 10})
  • capped : 默认值为false表示不设置上限,值为true表示设置上限
  • size : 当capped值为true时, 需要指定此参数, 表示上限大小,当文档达到上限时, 会将之前的数据覆盖, 单位是字节

查看当前数据库的集合

show collections

删除集合

db.集合名称.ddrop()

2.4 数据类型

下表为MongoDB中常用的几种数据类型

数据类型 说明
object id 文档ID
String 字符串,最常用,必须是有效的UTF-8
Boolean 存储一个布尔值,true或false
Integer 整数可以是32位或64位,这取决于服务器
Double 存储浮点值
Arrays 数组或列表,多个值存储到一个键
Object 用于嵌入式的文档,即一个值为一个文档
Null 存储Null值
Timestamp 时间戳
Date 存储当前日期或时间的UNIX时间格式
  • Object id
    • 每个文档都有一个属性,为_id,保证每个文档的唯一性
    • 可以自己去设置_id插入文档
    • 如果没有提供,那么MongoDB为每个文档提供了一个独特的_id,类型为objectID
    • objectID是一个12字节的十六进制数
      • 前4个字节为当前时间戳
      • 接下来3个字节的机器ID
      • 接下来的2个字节中MongoDB的服务进程id
      • 最后3个字节是简单的增量值

2.5 数据操作

插入

db.集合名称.insert(document)
  • 插入文档时,如果不指定_id参数,MongoDB会为文档分配一个唯一的ObjectId
  • 集合如果还没有被创建,则会自动创建集合
例子:
db.stu.insert({name:'gj',gender:1})

简单查询

db.集合名词.find()

更新

db.集合名称.update(
   <query>,
   <update>,
   {multi: <boolean>}
)
  • 参数query:查询条件,类似sql语句update中where部分
  • 参数update:更新操作符,类似sql语句update中set部分
  • 参数multi:可选,默认是false,表示只更新找到的第一条记录,值为true表示把满足条件的文档全部更新
例子
全文档更新
db.stu.update({name:'hr'},{name:'mnc'})


默认只修改一条数据,并且可以去修改文档结构

指定属性更新,通过操作符$set
db.stu.insert({name:'hr',gender:0})
db.stu.update({name:'hr'},{$set:{name:'hys'}})
修改多条匹配到的数据
db.stu.update({},{$set:{gender:0}},{multi:true})

想要多行修改,必须配合$set一同使用

保存

db.集合名称.save(document)

如果文档的_id已经存在则修改,如果文档的_id不存在或没有指定_id,则添加

例子
db.stu.save({_id:'20160102','name':'yk',gender:1})

删除

db.集合名称.remove(
   <query>,
   {
     justOne: <boolean>
   }
)
  • 参数query:删除的文档的条件
  • 参数justOne:可选,如果设为true或1,则只删除一条,默认false,表示删除多条
例子
只删除匹配到的第一条
db.stu.remove({gender:0},{justOne:true})
全部删除
db.stu.remove({})

2.6 数据查询

基本查询

方法 说明 语法
find() 查询 db.集合名称.find({条件文档})
findOne() 查询,只返回第一个 db.集合名称.findOne({条件文档})
pretty() 将结果格式化,在终端能看出效果 db.集合名称.find({条件文档}).pretty()

比较运算符

  • 等于,默认是等于判断,没有运算符
  • 小于$lt
  • 小于或等于$lte
  • 大于$gt
  • 大于或等于$gte
  • 不等于$ne
例子

查询年龄大于等于18的学生

db.stu.find({age:{$gte:18}})

逻辑运算符

查询时可以有多个条件,多个条件之间需要通过逻辑运算符连接

  • 逻辑与:默认是逻辑与的关系,没有单独的运算符
  • 逻辑或:使用$or[],中括号内为多个条件
例子

查询年龄大于18 或 性别为 0的学生,并且学生的姓名需要时gj

db.stu.find({$or:[{age:{$gte:18}},{gender:1}],name:'gj'})

范围运算符

使用"ParseError: KaTeX parse error: Expected 'EOF', got ',' at position 4: in",̲"nin" 判断是否在某个范围内

例子

查询年龄为18~28的学生

db.stu.find({age:{$in:[18,28]}})

支持正则表达式

使用 /表达式/$regex 编写正则表达式

例子

查询姓黄的学生

db.stu.find({name:/^黄/})
db.stu.find({name:{$regex:'^黄'}}})

自定义查询

使用$where后面写一个函数,返回满足条件的数据,这个函数需要返回一个boolean类型的值,实际上就是写一个js的代码

例子

查询年龄大于30的学生

db.stu.find({$where:function(){return this.age>20}})

this: 就是每一行的文档对象

Limit与Skip

方法 说明 语法
limit() 用于读取指定数量的文档 db.集合名称.find().limit(NUMBER)
skip() 用于跳过指定数量的文档 db.集合名称.find().skip(NUMBER)
  • limit
    • 参数NUMBER表示要获取文档的条数
    • 如果没有指定参数则显示集合中的所有文档
  • skip
    • 参数NUMBER表示跳过的记录条数,默认值为0

一起使用可以完成分页功能,例如:

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

投影

在查询到的返回结果中,只选择必要的字段,而不是选择一个文档的整个字段

语法:

db.集合名称.find({查询条件},{字段名称:1,...})
  • 参数为字段与值,值为1表示显示,值为0不显示
  • 对于需要显示的字段,设置为1即可,不设置即为不显示
    • 特殊:对于_id列默认是显示的,如果不显示需要明确设置为0

排序

方法sort(),用于对结果集进行排序
语法

db.集合名称.find().sort({字段:1,...})
  • 参数1为升序排列
  • 参数-1为降序排列

例1:根据性别降序,再根据年龄升序

db.stu.find().sort({gender:-1,age:1})

统计个数

方法count()用于统计结果集中文档条数

语法:

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

也可以:

db.集合名称.count({条件})

消除重复

方法distinct()对数据进行去重

db.集合名称.distinct('去重字段',{条件})

3. 高级操作

3.1 聚合aggregate

聚合(aggregate)主要用于计算数据,类似sql中的sum()、avg()
语法:

db.集合名称.aggregate([{管道:{表达式}}])

管道

管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的输入
例如:

ps ajx | grep mongo

在mongodb中,管道具有同样的作用,文档处理完毕后,通过管道进行下一次处理

常用管道:

  • $group:将集合中的文档分组,可用于统计结果
  • $match:过滤数据,只输出符合条件的文档
  • $project:修改输入文档的结构,如重命名、增加、删除字段、创建计算结果
  • $sort:将输入文档排序后输出
  • $limit:限制聚合管道返回的文档数
  • $skip:跳过指定数量的文档,并返回余下的文档
  • $unwind:将数组类型的字段进行拆分
$group

例子: 统计男生,女生的总人数

db.stu.aggregate([
    {$group:
        {
            _id:'$gender',
            counter:{$sum:1}
        }
    }
])
  • _id: 表示分组的一句,使用某个字段的格式为 $字段
  • counter: 是聚合后的数据,相当于列名,可以自定义
  • $sum: 求和
    • 如果是常数,则统计条数,相当于1条数据 结果加几
    • 也可以基于某个字段求和,例如 { sum:′sum:'sum:age'},则会将结果的年龄进行求和操作

Grouvp by null

将集合中所有文档 分为一组

例子: 求学生总人数,平均年龄

db.stu.aggregate([
    {$group:
        {
            _id:null,
            counter:{$sum:1},
            avgAge:{$avg:'$age'}
        }
    }
])

透视数据

例子 : 统计学生性别及学生姓名

db.stu.aggregate([
    {$group:
        {
            _id:'$gender',
            name:{$push:'$name'}
        }
    }
])

使用 $$ROOT可以将整个文档内容加入到结果集的数组中:

db.stu.aggregate([
    {$group:
        {
            _id:'$gender',
            name:{$push:'$$ROOT'}
        }
    }
])

$match

  • 用于过滤数据,只输出符合条件的文档

  • 使用MongoDB的标准查询操作

  • 例: 查询年龄大于20的学生v

    db.stu.aggregate([
        {$match:{age:{$gt:20}}}
    ])
    
  • 例: 查询年龄大于20的男生,女生人数

    db.stu.aggregate([
        {$match:{age:{$gt:20}}},
        {$group:{_id:'$gender',counter:{$sum:1}}}
    ])
    

将第一个管道的输出作为第二个管道的输入

$project

修改输入文档的结构,如重命名、增加、删除字段、创建计算结果,用来做投影的

查询学生的姓名,年龄

db.stu.aggregate([
    {$project:{_id:0,name:1,age:1}}
])

查询男生,女生人数,输出人数

db.stu.aggregate([
    {$group:{_id:'$gender',counter:{$sum:1}}},
    {$project:{_id:0,counter:1}}
])

$sort

将输入文档排序后输出

查询学生信息,按年龄升序

db.stu.aggregate([{$sort:{age:1}}])

查询男生,女生人数,按人数升序

db.stu.aggregate([
    {$group:{_id:'$gender',counter:{$sum:1}}},
    {$sort:{counter:-1}}
])

$limit

限制聚合管道返回的文档数

查询2条学生信息

db.stu.aggregate([{$limit:2}])

skip

跳过指定数量的文档,并返回余下的文档

查询从第3条开始的学生信息

db.stu.aggregate([{$skip:2}])

统计男生,女生人数,按人数升序,取第二条数据

db.stu.aggregate([
    {$group:{_id:'$gender',counter:{$sum:1}}},
    {$sort:{counter:1}},
    {$skip:1},
    {$limit:1}
])

注意顺序:先写skip,再写limit

$unwind

将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值

语法1

对某字段值进行拆分,相当于$push的逆操作

db.集合名称.aggregate([{$unwind:'$字段名称'}])

构造数据

db.t2.insert({_id:1,item:'t-shirt',size:['S','M','L']})

查询

db.t2.aggregate([{$unwind:'$size'}])

语法2

对某字段值进行拆分
处理空数组、非数组、无字段、null情况

db.inventory.aggregate([{
    $unwind:{
        path:'$字段名称',
        preserveNullAndEmptyArrays:<boolean>#防止数据丢失
    }
}])

构造数据

db.t3.insert([
{ "_id" : 1, "item" : "a", "size": [ "S", "M", "L"] },
{ "_id" : 2, "item" : "b", "size" : [ ] },
{ "_id" : 3, "item" : "c", "size": "M" },
{ "_id" : 4, "item" : "d" },
{ "_id" : 5, "item" : "e", "size" : null }
])

使用语法1查询

db.t3.aggregate([{$unwind:'$size'}])

发现对于空数组,无字段,null的文档,都被丢弃了,要想不被丢弃,使用语法2查询

db.t3.aggregate([{$unwind:{path:'$size',preserveNullAndEmptyArrays:true}}])

表达式

处理输入文档并输出
语法:

表达式:'$列名'

常用表达式:

表达式名称 描述
$sum: 计算总和,$sum:1同count表示计数
$avg: 计算平均值
$min: 获取最小值
$max: 获取最大值
$push: 在结果文档中插入值到一个数组中
$first: 根据资源文档的排序获取第一个文档数据
$last: 根据资源文档的排序获取最后一个文档数据
  • $push:

3.2 索引

mogodb中也支持索引来提升查询速度

步骤一: 创建大量数据

向集合中插入10万条数据

for(i=0;i<100000;i++){
    db.t1.insert({name:'test'+i,age:i})
}

mongodb 的shell 是js的编译器,是可以执行js代码的,插入的时间会稍微有些长

步骤二: 数据查找分析性能

查找名为test10000的文档,使用explain()命令进行性能分析

db.t1.find({name:'test10000'}).explain('executionStats')

  • executionStats下的executionTimeMillis表示整体查询时间,单位是毫秒

步骤三: 创建索引

语法:

db.集合.ensureIndex({属性:1})
  • 1表示升序,-1表示降序
db.t1.ensureIndex({name:1})

步骤四: 验证查询时间

索引的命令

  • 建立唯一索引,实现唯一约束的功能
    db.t1.ensureIndex({"name":1},{"unique",true})
    
  • 联合索引,对多个属性建立一个索引,按照find()出现的顺序
    db.t1.ensureIndex({name:1,age:1})
    
  • 查看文档所有索引
    db.t1.getIndexes()
    
  • 删除索引
    db.t1.dropIndexes('索引名称')
    

3.3 安全

超级管理员

  • 为了更安全的访问mongodb,需要访问者提供用户名和密码,于是需要在mongodb中创建用户
  • 采用了角色-用户-数据库的安全管理方式
  • 常用系统角色如下:
    • root:只在admin数据库中可用,超级账号,超级权限
    • Read:允许用户读取指定数据库
    • readWrite:允许用户读写指定数据库

创建超级管理用户

use admin
db.createUser({
    user:'admin',
    pwd:'123',
    roles:[{role:'root',db:'admin'}]
})

启用安全认证

在mongod.conf中添加:

security:
  authorization: enabled

冒号后有空格

然后重启服务

连接:

 mongo -u 'admin' -p '123' --authenticationDatabase 'admin'

普通用户

使用超级管理员登录,然后创建用户,先use要创建用户的数据库

db.createUser({
    user:'t1',
    pwd:'123',
    roles:[{role:'readWrite',db:'test1'}]
})

修改用户:

db.updateUser('t1',{pwd:'456'})

整个流程

4 与python交互

安装python包

pip install pymongo

引入包

from pymongo import *

连接,创建客户端

client=MongoClient('mongodb://localhost:27017') # 无安全验证
client=MongoClient('mongodb://用户名:密码@loacalhost:27017/数据库名称') # 有安全验证

获得数据库test1

db=client.test1

类collection

主要方法有:

  • insert_one
  • insert_many
  • update_one
  • update_many
  • delete_one
  • delete_many
  • find_one
  • find

获得集合stu

stu=db.stu

添加文档

s1={
     
     name:'gj',age:18}
s1_id = stu.insert_one(s1).inserted_id

查找一个文档

s2=stu.find_one()

查找多个文档

for cur in stu.find():
    print cur

获取文档个数

print stu.count()
    #coding=utf-8


from pymongo import MongoClient

# 获得客户端,建立连接

client = MongoClient('mongodb://localhost:27017')

# 切换数据库
db = client.py3

# 获取集合
stu = db.stu

# 增加
s1 = stu.insert_one({
     
     'name': 'PYTHON','age': '18', 'gender': 0})
print(s1.inserted_id)
print(s1.acknowledged)  # 是否插入成功

# 修改
stu.update_one({
     
     'name':'PYTHON'},{
     
     '$set':{
     
     'name:':'abc'}})

# 删除
stu.delete_many({
     
     'name':'abc'})

# 查询
cursor = stu.find({
     
     'age':{
     
     '$gt':18}}).skip(1).limit(1)

for s in cursor:
    print(s)

猜你喜欢

转载自blog.csdn.net/cfy137000/article/details/79291184