Spider_Man_5.2 の Mongodb_使用

一:简介

MongoDB是一款强大、灵活、且易于扩展的通用型数据库
一、易用性html

复制代码
MongoDB是一个面向文档(document-oriented)的数据库,而不是关系型数据库。
不采用关系型主要是为了得到更好得扩展性。固然还有一些其余好处,与关系数据库相比,面向文档的数据库再也不有“行“(row)的概念取而代之的是更为灵活的“文档”(document)模型。
经过在文档中嵌入文档和数组,面向文档的方法可以仅使用一条记录来表现复杂的层级关系,这与现代的面向对象语言的开发者对数据的见解一致。 另外,再也不有预约义模式(predefined schema):文档的键(key)和值(value)再也不是固定的类型和大小。因为没有固定的模式,根据须要添加或删除字段变得更容易了。一般因为开发者可以进行快速迭代,因此开发进程得以加快。并且,实验更容易进行。开发者能尝试大量的数据模型,从中选一个最好的。
复制代码

二、易扩展性python

复制代码
应用程序数据集的大小正在以难以想象的速度增加。随着可用带宽的增加和存储器价格的降低,即便是一个小规模的应用程序,须要存储的数据量也可能大的惊人,甚至超出
了不少数据库的处理能力。过去很是罕见的T级数据,如今已是司空见惯了。
因为须要存储的数据量不断增加,开发者面临一个问题:应该如何扩展数据库,分为纵向扩展和横向扩展,纵向扩展是最省力的作法,但缺点是大型机通常都很是贵,并且
当数据量达到机器的物理极限时,花再多的钱也买不到更强的机器了,此时选择横向扩展更为合适,但横向扩展带来的另一个问题就是须要管理的机器太多。
MongoDB的设计采用横向扩展。面向文档的数据模型使它能很容易地在多台服务器之间进行数据分割。MongoDB可以自动处理跨集群的数据和负载,自动从新分配文档,以及将
用户的请求路由到正确的机器上。这样,开发者可以集中精力编写应用程序,而不须要考虑如何扩展的问题。若是一个集群须要更大的容量,只须要向集群添加新服务器,MongoDB就会自动将现有的数据向新服务器传送
复制代码

三、丰富的功能mysql

复制代码
MongoDB做为一款通用型数据库,除了可以建立、读取、更新和删除数据以外,还提供了一系列不断扩展的独特功能
#一、索引
支持通用二级索引,容许多种快速查询,且提供惟一索引、复合索引、地理空间索引、全文索引

#二、聚合
支持聚合管道,用户能经过简单的片断建立复杂的集合,并经过数据库自动优化

#三、特殊的集合类型
支持存在时间有限的集合,适用于那些将在某个时刻过时的数据,如会话session。相似地,MongoDB也支持固定大小的集合,用于保存近期数据,如日志

#四、文件存储
支持一种很是易用的协议,用于存储大文件和文件元数据。MongoDB并不具有一些在关系型数据库中很广泛的功能,如连接join和复杂的多行事务。省略
这些的功能是处于架构上的考虑,或者说为了获得更好的扩展性,由于在分布式系统中这两个功能难以高效地实现
复制代码

四、卓越的性能正则表达式

MongoDB的一个主要目标是提供卓越的性能,这很大程度上决定了MongoDB的设计。MongoDB把尽量多的内存用做缓存cache,视图为每次查询自动选择正确的索引。
总之各方面的设计都旨在保持它的高性能
虽然MongoDB很是强大并试图保留关系型数据库的不少特性,但它并不追求具有关系型数据库的全部功能。只要有可能,数据库服务器就会将处理逻辑交给客户端。这种精简方式的设计是MongoDB可以实现如
此高性能的缘由之一

 

二:MongoDB基础知识

 

一、文档是MongoDB的核心概念。文档就是键值对的一个有序集{'msg':'hello','foo':3}。相似于python中的有序字典。sql

复制代码
须要注意的是:
#一、文档中的键/值对是有序的。
#二、文档中的值不只能够是在双引号里面的字符串,还能够是其余几种数据类型(甚至能够是整个嵌入的文档)。
#三、MongoDB区分类型和大小写。
#四、MongoDB的文档不能有重复的键。
#五、文档中的值能够是多种不一样的数据类型,也能够是一个完整的内嵌文档。文档的键是字符串。除了少数例外状况,键可使用任意UTF-8字符。

文档键命名规范:
#一、键不能含有\0 (空字符)。这个字符用来表示键的结尾。
#二、.和$有特别的意义,只有在特定环境下才能使用。
#三、如下划线"_"开头的键是保留的(不是严格要求的)。
复制代码

二、集合就是一组文档。若是将MongoDB中的一个文档比喻为关系型数据的一行,那么一个集合就是至关于一张表mongodb

复制代码
#一、集合存在于数据库中,一般状况下为了方便管理,不一样格式和类型的数据应该插入到不一样的集合,但其实集合没有固定的结构,这意味着咱们彻底能够把不一样格式和类型的数据通通插入一个集合中。

#二、组织子集合的方式就是使用“.”,分隔不一样命名空间的子集合。
好比一个具备博客功能的应用可能包含两个集合,分别是blog.posts和blog.authors,这是为了使组织结构更清晰,这里的blog集合(这个集合甚至不须要存在)跟它的两个子集合没有任何关系。
在MongoDB中,使用子集合来组织数据很是高效,值得推荐

#三、当第一个文档插入时,集合就会被建立。合法的集合名:
集合名不能是空字符串""。
集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。
集合名不能以"system."开头,这是为系统集合保留的前缀。
用户建立的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是由于某些系统生成的集合中包含该字符。除非你要访问这种系统建立的集合,不然千万不要在名字里出现$。
复制代码

 三、数据库:在MongoDB中,多个文档组成集合,多个集合能够组成数据库shell

复制代码
数据库也经过名字来标识。数据库名能够是知足如下条件的任意UTF-8字符串:
#一、不能是空字符串("")。
#二、不得含有' '(空格)、.、$、/、\和\0 (空字符)。
#三、应所有小写。
#四、最多64字节。

有一些数据库名是保留的,能够直接访问这些有特殊做用的数据库。
#一、admin: 从身份认证的角度讲,这是“root”数据库,若是将一个用户添加到admin数据库,这个用户将自动得到全部数据库的权限。再者,一些特定的服务器端命令也只能从admin数据库运行,如列出全部数据库或关闭服务器
#二、local: 这个数据库永远都不能够复制,且一台服务器上的全部本地集合均可以存储在这个数据库中
#三、config: MongoDB用于分片设置时,分片信息会存储在config数据库中
复制代码

四、强调:把数据库名添加到集合名前,获得集合的彻底限定名,即命名空间数据库

例如:
若是要使用cms数据库中的blog.posts集合,这个集合的命名空间就是 cmd.blog.posts。命名空间的长度不得超过121个字节,且在实际使用中应该小于100个字节

 

三:安装

1.关于安装:友情连接:Spider_Man_5.1 の Mongodb_安装编程

2:关于帐号管理:json

#帐号管理:https://docs.mongodb.com/master/tutorial/enable-authentication/
#一、建立帐号
use admin
db.createUser(
  {
    user: "root",
    pwd: "123",
    roles: [ { role: "root", db: "admin" } ]
  }
)

use test
db.createUser(
  {
    user: "fff",
    pwd: "123",
    roles: [ { role: "readWrite", db: "test" },
             { role: "read", db: "db1" } ]
  }
)


#二、重启数据库
mongod --remove
mongod --config "存放目录\mongodb\mongod.cfg" --bind_ip 0.0.0.0 --install --auth

#三、登陆:注意使用双引号而非单引号
mongo --port 27017 -u "root" -p "123" --authenticationDatabase "admin"

也能够在登陆以后用db.auth("帐号","密码")登陆
mongo
use admin
db.auth("root","123")

3:命令行shell

#一、mongo 127.0.0.1:27017/config #链接到任何数据库config

#二、mongo --nodb #不链接到任何数据库

#三、启动以后,在须要时运行new Mongo(hostname)命令就能够链接到想要的mongod了:
> conn=new Mongo('127.0.0.1:27017')
connection to 127.0.0.1:27017
> db=conn.getDB('admin')
admin

#四、help查看帮助

#五、mongo是一个简化的JavaScript shell,是能够执行JavaScript脚本的

 

四:基本数据类型

一、在概念上,MongoDB的文档与Javascript的对象相近,于是能够认为它相似于JSON。JSON(http://www.json.org)是一种简单的数据表示方式:其规范仅用一段文字就能描述清楚(其官网证实了这点),且仅包含六种数据类型。

二、这样有不少好处:易于理解、易于解析、易于记忆。然而从另外一方面说,由于只有null、布尔、数字、字符串、数字和对象这几种数据类型,因此JSON的表达能力有必定的局限。

三、虽然JSON具有的这些类型已经具备很强的表现力,但绝大数应用(尤为是在于数据库打交道时)都还须要其余一些重要的类型。例如,JSON没有日期类型,这使得本来容易日期处理变得烦人。另外,JSON只有一种数字类型,没法区分浮点数和整数,更别区分32位和64位了。再者JSON没法表示其余一些通用类型,如正则表达式或函数。

四、MongoDB在保留了JSON基本键/值对特性的基础上,添加了其余一些数据类型。在不一样的编程语言下,这些类型的确切表示有些许差别。下面说明了MongoDB支持的其余通用类型,以及如何正在文档中使用它们

#一、null:用于表示空或不存在的字段
d={'x':null}
#二、布尔型:true和false
d={'x':true,'y':false}
#三、数值
d={'x':3,'y':3.1415926}
#四、字符串
d={'x':'fff'}
#五、日期
d={'x':new Date()}
d.x.getHours()
#六、正则表达式
d={'pattern':/^egon.*?nb$/i}

正则写在//内,后面的i表明:
i 忽略大小写
m 多行匹配模式
x 忽略非转义的空白字符
s 单行匹配模式

#七、数组
d={'x':[1,'a','v']}

#八、内嵌文档
user={'name':'fff','addr':{'country':'China','city':'LB'}}
user.addr.country

#九、对象id:是一个12字节的ID,是文档的惟一标识,不可变
d={'x':ObjectId()}

五、_id 和 ObjectId

MongoDB中存储的文档必须有一个"_id"键。这个键的值能够是任意类型,默认是个ObjectId对象。
在一个集合里,每一个文档都有惟一的“_id”,确保集合里每一个文档都能被惟一标识。
不一样集合"_id"的值能够重复,但同一集合内"_id"的值必须惟一

#一、ObjectId
ObjectId是"_id"的默认类型。由于设计MongoDb的初衷就是用做分布式数据库,因此可以在分片环境中生成
惟一的标识符很是重要,而常规的作法:在多个服务器上同步自动增长主键既费时又费力,这就是MongoDB采用
ObjectId的缘由。
ObjectId采用12字节的存储空间,是一个由24个十六进制数字组成的字符串
    0|1|2|3|   4|5|6|     7|8    9|10|11    
    时间戳      机器      PID    计数器
若是快速建立多个ObjectId,会发现每次只有最后几位有变化。另外,中间的几位数字也会变化(要是在建立过程当中停顿几秒)。
这是ObjectId的建立方式致使的,如上图

时间戳单位为秒,与随后5个字节组合起来,提供了秒级的惟一性。这个4个字节隐藏了文档的建立时间,绝大多数驱动程序都会提供
一个方法,用于从ObjectId中获取这些信息。

由于使用的是当前时间,不少用户担忧要对服务器进行时钟同步。其实不必,由于时间戳的实际值并不重要,只要它老是不停增长就好。
接下来3个字节是所在主机的惟一标识符。一般是机器主机名的散列值。这样就能够保证不一样主机生成不一样的ObjectId,不产生冲突

接下来连个字节确保了在同一台机器上并发的多个进程产生的ObjectId是惟一的

前9个字节确保了同一秒钟不一样机器不一样进程产生的ObjectId是惟一的。最后3个字节是一个自动增长的 计数器。确保相同进程的同一秒产生的
ObjectId也是不同的。

#二、自动生成_id
若是插入文档时没有"_id"键,系统会自帮你建立 一个。能够由MongoDb服务器来作这件事。
但一般会在客户端由驱动程序完成。这一作法很是好地体现了MongoDb的哲学:能交给客户端驱动程序来作的事情就不要交给服务器来作。
这种理念背后的缘由是:即使是像MongoDB这样扩展性很是好的数据库,扩展应用层也要比扩展数据库层容易的多。将工做交给客户端作就
减轻了数据库扩展的负担。
_id & ObjectId

 

五:CURD 操做

一、数据库操做(use,show,dropDatabase)

#一、增
use config #若是数据库不存在,则建立数据库,不然切换到指定数据库。

#二、查
show dbs #查看全部
能够看到,咱们刚建立的数据库config并不在数据库的列表中, 要显示它,咱们须要向config数据库插入一些数据。
db.table1.insert({'a':1})

#三、删
use config #先切换到要删的库下
db.dropDatabase() #删除当前库

 

二、集合操做

#一、增
当第一个文档插入时,集合就会被建立
> use database1
switched to db database1
> db.table1.insert({'a':1})
WriteResult({ "nInserted" : 1 })
> db.table2.insert({'b':2})
WriteResult({ "nInserted" : 1 })

#二、查
> show tables
table1
table2

#三、删
> db.table1.drop()
true
> show tables
table2
关于集合操做

 

三、文档操做

  3.1 增:

#一、没有指定_id则默认ObjectId,_id不能重复,且在插入后不可变

#二、插入单条
user0={
    "name":"pp",
    "age":10,
    'hobbies':['music','read','dancing'],
    'addr':{
        'country':'China',
        'city':'BJ'
    }
}

db.test.insert(user0)
db.test.find()

#三、插入多条
user1={
    "_id":1,
    "name":"ww",
    "age":10,
    'hobbies':['music','read','dancing'],
    'addr':{
        'country':'China',
        'city':'weifang'
    }
}

user2={
    "_id":2,
    "name":"wusir",
    "age":20,
    'hobbies':['music','read','run'],
    'addr':{
        'country':'China',
        'city':'hebei'
    }
}


user3={
    "_id":3,
    "name":"nazha",
    "age":30,
    'hobbies':['music','drink'],
    'addr':{
        'country':'China',
        'city':'heibei'
    }
}

user4={
    "_id":4,
    "name":"eva",
    "age":40,
    'hobbies':['music','read','dancing','tea'],
    'addr':{
        'country':'China',
        'city':'BJ'
    }
}

user5={
    "_id":5,
    "name":"ff",
    "age":50,
    'hobbies':['music','read',],
    'addr':{
        'country':'China',
        'city':'henan'
    }
}
db.user.insertMany([user1,user2,user3,user4,user5])
单条插入与多条插入

  3.2 删:

#一、删除多个中的第一个
db.user.deleteOne({ 'age': 8 })

#二、删除国家为China的所有
db.user.deleteMany( {'addr.country': 'China'} ) 

#三、删除所有
db.user.deleteMany({}) 
deleteOne & deleteMany

  3.3 改:

update() 方法用于更新已存在的文档。语法格式以下:
db.collection.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   }
)
参数说明:对比update db1.t1 set name='FFF',sex='Male' where name='fff' and age=18;

query : 至关于where条件。
update : update的对象和一些更新的操做符(如$,$inc...等,至关于set后面的
upsert : 可选,默认为false,表明若是不存在update的记录不更新也不插入,设置为true表明插入。
multi : 可选,默认为false,表明只更新找到的第一条记录,设为true,表明更新找到的所有记录。
writeConcern :可选,抛出异常的级别。

更新操做是不可分割的:若两个更新同时发送,先到达服务器的先执行,而后执行另一个,不会破坏文档。

update语法介绍
update语法介绍
#注意:除非是删除,不然_id是始终不会变的
#一、覆盖式:
db.user.update({'age':20},{"name":"Wxx","hobbies_count":3})
是用{"_id":2,"name":"Wxx","hobbies_count":3}覆盖原来的记录

#二、一种最简单的更新就是用一个新的文档彻底替换匹配的文档。这适用于大规模式迁移的状况。例如
var obj=db.user.findOne({"_id":2})

obj.username=obj.name+'SB'
obj.hobbies_count++
delete obj.age

db.user.update({"_id":2},obj)
覆盖式
#设置:$set

一般文档只会有一部分须要更新。可使用原子性的更新修改器,指定对文档中的某些字段进行更新。
更新修改器是种特殊的键,用来指定复杂的更新操做,好比修改、增长后者删除

#一、update db1.user set  name="WXX" where id = 2
db.user.update({'_id':2},{"$set":{"name":"WXX",}})

#二、没有匹配成功则新增一条{"upsert":true}
db.user.update({'_id':6},{"$set":{"name":"pp","age":18}},{"upsert":true})

#三、默认只改匹配成功的第一条,{"multi":改多条}
db.user.update({'_id':{"$gt":4}},{"$set":{"age":28}})
db.user.update({'_id':{"$gt":4}},{"$set":{"age":38}},{"multi":true})

#四、修改内嵌文档,把名字为alex的人所在的地址国家改为Japan
db.user.update({'name':"ww"},{"$set":{"addr.country":"Japan"}})

#五、把名字为alex的人的地2个爱好改为piao
db.user.update({'name':"ww"},{"$set":{"hobbies.1":"piao"}})

#六、删除alex的爱好,$unset
db.user.update({'name':"ww"},{"$unset":{"hobbies":""}})
设置:$set
增长和减小:$inc

#一、全部人年龄增长一岁
db.user.update({},
    {
        "$inc":{"age":1}
    },
    {
        "multi":true
    }
    )
#二、全部人年龄减小5岁
db.user.update({},
    {
        "$inc":{"age":-5}
    },
    {
        "multi":true
    }
    )
增长和减小:$inc
#添加删除数组内元素
    
往数组内添加元素:$push
#一、为名字为qwe的人添加一个爱好read
db.user.update({"name":"qwe"},{"$push":{"hobbies":"read"}})

#二、为名字为qwe的人一次添加多个爱好tea,dancing
db.user.update({"name":"qwe"},{"$push":{
    "hobbies":{"$each":["tea","dancing"]}
}})

按照位置且只能从开头或结尾删除元素:$pop
#三、{"$pop":{"key":1}} 从数组末尾删除一个元素

db.user.update({"name":"qwe"},{"$pop":{
    "hobbies":1}
})

#四、{"$pop":{"key":-1}} 从头部删除
db.user.update({"name":"qwe"},{"$pop":{
    "hobbies":-1}
})

#五、按照条件删除元素,:"$pull" 把符合条件的通通删掉,而$pop只能从两端删
db.user.update({'addr.country':"China"},{"$pull":{
    "hobbies":"read"}
},
{
    "multi":true
}
)
添加删除组内元素:$push,$pop,$pull
#避免添加剧复:"$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'
            ]
            }
        }
    }
)
避免添加剧复:$addToSet
#一、了解:限制大小"$slice",只留最后n个

db.user.update({"_id":5},{
    "$push":{"hobbies":{
        "$each":["read",'music','dancing'],
        "$slice":-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"或者"$sort"与"$push"配合使用,且必须使用"$eah"
Other

  3.4 查:  

# SQL:=,!=,>,<,>=,<=
# MongoDB:{key:value}表明什么等于什么,"$ne","$gt","$lt","gte","lte",其中"$ne"能用于全部数据类型

#一、select * from db1.user where name = "pp";
db.user.find({'name':'pp'})

#二、select * from db1.user where name != "pp";
db.user.find({'name':{"$ne":'pp'}})

#三、select * from db1.user where id > 2;
db.user.find({'_id':{'$gt':2}})

#四、select * from db1.user where id < 3;
db.user.find({'_id':{'$lt':3}})

#五、select * from db1.user where id >= 2;
db.user.find({"_id":{"$gte":2,}})

#六、select * from db1.user where id <= 2;
db.user.find({"_id":{"$lte":2}})
比较运算:"$ne","$gt","$lt","gte","lte"
# SQL:and,or,not
# MongoDB:字典中逗号分隔的多个条件是and关系,"$or"的条件放到[]内,"$not"

#一、select * from db1.user where id >= 2 and id < 4;
db.user.find({'_id':{"$gte":2,"$lt":4}})

#二、select * from db1.user where id >= 2 and age < 40;
db.user.find({"_id":{"$gte":2},"age":{"$lt":40}})

#三、select * from db1.user where id >= 5 or name = "pp";
db.user.find({
    "$or":[
        {'_id':{"$gte":5}},
        {"name":"pp"}
        ]
})

#四、select * from db1.user where id % 2=1;
db.user.find({'_id':{"$mod":[2,1]}})

#五、上题,取反
db.user.find({'_id':{"$not":{"$mod":[2,1]}}})
逻辑运算:字典中逗号分隔的多个条件是and关系,"$or"的条件放到[]内,"$not"
# SQL:in,not in
# MongoDB:"$in","$nin"

#一、select * from db1.user where age in (20,30,31);
db.user.find({"age":{"$in":[20,30,31]}})

#二、select * from db1.user where name not in ('pp','nazha');
db.user.find({"name":{"$nin":['pp','nazha']}})
成员运算:$in & $nin
# SQL: regexp 正则
# MongoDB: /正则表达/i

#一、select * from db1.user where name regexp '^j.*?(g|n)$';
db.user.find({'name':/^e.*?(g|n)$/i})
正则匹配:/正则表达/i
# select name,age from db1.user where id=3;
db.user.find({'_id':3},{'_id':0,'name':1,'age':1})
获取指定字段
#一、查看有dancing爱好的人
db.user.find({'hobbies':'dancing'})

#二、查看既有dancing爱好又有tea爱好的人
db.user.find({
    'hobbies':{
        "$all":['dancing','tea']
        }
})

#三、查看第4个爱好为tea的人
db.user.find({"hobbies.3":'tea'})

#四、查看全部人最后两个爱好
db.user.find({},{'hobbies':{"$slice":-2},"age":0,"_id":0,"name":0,"addr":0})

#五、查看全部人的第2个到第3个爱好
db.user.find({},{'hobbies':{"$slice":[1,2]},"age":0,"_id":0,"name":0,"addr":0})

> db.blog.find().pretty()
{
        "_id" : 1,
        "name" : "pp的女友",
        "comments" : [
                {
                        "name" : "pp",
                        "content" : "ww是谁???",
                        "thumb" : 200
                },
                {
                        "name" : "glm",
                        "content" : "我去,真的假的",
                        "thumb" : 10000000...
                },
                {
                        "name" : "yxx",
                        "content" : "吃喝嫖赌抽,欠下两个亿",
                        "thumb" : 40
                },
                {
                        "name" : "ff",
                        "content" : "xxx",
                        "thumb" : 0
                }
        ]
}
db.blog.find({},{'comments':{"$slice":-2}}).pretty() #查询最后两个
db.blog.find({},{'comments':{"$slice":[1,2]}}).pretty() #查询1到2
查询数组
# 排序:--1表明升序,-1表明降序
db.user.find().sort({"name":1,})
db.user.find().sort({"age":-1,'_id':1})
排序:sort
# 分页:--limit表明取多少个document,skip表明跳过前多少个document。 
db.user.find().sort({'age':1}).limit(1).skip(2)
分页:limit表明取多少个document,skip表明跳过前多少个document
# 获取数量
db.user.count({'age':{"$gt":30}}) 

或者
db.user.find({'age':{"$gt":30}}).count()
获取数量:count
#一、{'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 }

#二、查找全部
db.user.find() #等同于db.user.find({})
db.user.find().pretty()

#三、查找一个,与find用法一致,只是只取匹配成功的第一个
db.user.findOne({"_id":{"$gt":3}})
Other

 

4:聚合!!!

若是你有数据存储在MongoDB中,你想作的可能就不只仅是将数据提取出来那么简单了;你可能但愿对数据进行分析并加以利用。MongoDB提供了如下聚合工具:
一、聚合框架 二、MapReduce(详见MongoDB权威指南) 三、几个简单聚合命令:count、distinct和group。(详见MongoDB权威指南)

#聚合框架:
可使用多个构件建立一个管道,上一个构件的结果传给下一个构件。
这些构件包括(括号内为构件对应的操做符):筛选($match)、投射($project)、分组($group)、排序($sort)、限制($limit)、跳过($skip)
不一样的管道操做符能够任意组合,重复使用

import datetime
from pymongo import MongoClient


# 数据准备
client = MongoClient()
table = client['db1']['emp']
l=[
('pp','male',18,'20170301','eat_god',7300.33,401,1), #如下是授业解惑的
('ww','male',78,'20150302','teacher',1000000.31,401,1),
('ff','male',81,'20130305','teacher',8300,401,1),
('wusir','male',73,'20140701','teacher',3500,401,1),
('peiqi','male',28,'20121101','teacher',2100,401,1),
('eva_jing','female',18,'20110211','teacher',9000,401,1),
('shaowei','male',18,'19000301','teacher',30000,401,1),
('gaylao','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)

# 聚合框架:
# 可使用多个构件建立一个管道,上一个构件的结果传给下一个构件。
# 这些构件包括(括号内为构件对应的操做符):筛选($match)、投射($project)、分组($group)、排序($sort)、限制($limit)、跳过($skip)
# 不一样的管道操做符能够任意组合,重复使用



# ################################################  筛选
# {"$match":{"字段":"条件"}},可使用任何经常使用查询操做符$gt,$lt,$in等

# select * from db1.emp where post='teacher'
# db.emp.aggregate({'$match':{'post':'teacher'}})
# """
# { "_id" : 1, "name" : "ww", "sex" : "male", "age" : 78, "hire_date" : ISODate("2015-03-02T00:00:00Z"), "post" : "teacher", "salary" : 1000000.31 }
# { "_id" : 2, "name" : "ff", "sex" : "male", "age" : 81, "hire_date" : ISODate("2013-03-05T00:00:00Z"), "post" : "teacher", "salary" : 8300 }
# { "_id" : 3, "name" : "wusir", "sex" : "male", "age" : 73, "hire_date" : ISODate("2014-07-01T00:00:00Z"), "post" : "teacher", "salary" : 3500 }
# { "_id" : 4, "name" : "peiqi", "sex" : "male", "age" : 28, "hire_date" : ISODate("2012-11-01T00:00:00Z"), "post" : "teacher", "salary" : 2100 }
# { "_id" : 5, "name" : "eva_jing", "sex" : "female", "age" : 18, "hire_date" : ISODate("2011-02-11T00:00:00Z"), "post" : "teacher", "salary" : 9000 }
# { "_id" : 6, "name" : "shaowei", "sex" : "male", "age" : 18, "hire_date" : ISODate("1900-03-01T00:00:00Z"), "post" : "teacher", "salary" : 30000 }
# { "_id" : 7, "name" : "gaylao", "sex" : "male", "age" : 48, "hire_date" : ISODate("2010-11-11T00:00:00Z"), "post" : "teacher", "salary" : 10000 }
# """

# select * from db1.emp where id > 3 group by post
db.emp.aggregate({'$match':{'_id':{'$gt':3}}},
                 {'$group':{'_id':'$post'}}
                 )
"""
{ "_id" : "sale" }
{ "_id" : "operation" }
{ "_id" : "teacher" }
"""

# select * from db1.emp where id > 3 group by post having avg(salary) > 10000;
db.emp.aggregate(
        {'$match':{'_id':{'$gt':3}}},
    {'$group':{'_id':'post','avg_salary':{'$avg':'$salary'}}},
{'$match':{'avg_salary':{'$gt':10000}}}
)

#{ "_id" : "post", "avg_salary" : 10578.685714285715 }



###############################################  投射:{"$project":{"要保留的字段名":1,"要去掉的字段名":0,"新增的字段名":"表达式"}}

#一、select name,post,(age+1) as new_age from db1.emp;
db.emp.aggregate({
    '$project':{'name':1,'post':1,
                'new_age':{'$add':['$age',1]}
                }
})

'''
{ "_id" : 0, "name" : "pp", "post" : "eat_god", "new_age" : 19 }
{ "_id" : 1, "name" : "ww", "post" : "teacher", "new_age" : 79 }
{ "_id" : 2, "name" : "ff", "post" : "teacher", "new_age" : 82 }
{ "_id" : 3, "name" : "wusir", "post" : "teacher", "new_age" : 74 }
{ "_id" : 4, "name" : "peiqi", "post" : "teacher", "new_age" : 29 }
{ "_id" : 5, "name" : "eva_jing", "post" : "teacher", "new_age" : 19 }
{ "_id" : 6, "name" : "shaowei", "post" : "teacher", "new_age" : 19 }
{ "_id" : 7, "name" : "gaylao", "post" : "teacher", "new_age" : 49 }
{ "_id" : 8, "name" : "歪歪", "post" : "sale", "new_age" : 49 }
{ "_id" : 9, "name" : "丫丫", "post" : "sale", "new_age" : 39 }
{ "_id" : 10, "name" : "丁丁", "post" : "sale", "new_age" : 19 }
{ "_id" : 11, "name" : "星星", "post" : "sale", "new_age" : 19 }
{ "_id" : 12, "name" : "格格", "post" : "sale", "new_age" : 29 }
{ "_id" : 13, "name" : "张野", "post" : "operation", "new_age" : 29 }
{ "_id" : 14, "name" : "程咬金", "post" : "operation", "new_age" : 19 }
{ "_id" : 15, "name" : "程咬银", "post" : "operation", "new_age" : 19 }
{ "_id" : 16, "name" : "程咬铜", "post" : "operation", "new_age" : 19 }
{ "_id" : 17, "name" : "程咬铁", "post" : "operation", "new_age" : 19 }
'''


#二、表达式之数学表达式
# {"$add":[expr1,expr2,...,exprN]} #相加
# {"$subtract":[expr1,expr2]} #第一个减第二个
# {"$multiply":[expr1,expr2,...,exprN]} #相乘
# {"$divide":[expr1,expr2]} #第一个表达式除以第二个表达式的商做为结果
# {"$mod":[expr1,expr2]} #第一个表达式除以第二个表达式获得的余数做为结果

#三、表达式之日期表达式¥year,$month,$week,$dayOfMonth,$dayOfWeek,$dayOfYear,$hour,$minute,$second
#例如:select name,date_format("%Y") as hire_year from db1.emp
db.emp.aggregate(
    {"$project":{"name":1,"hire_year":{"$year":"$hire_date"}}})
"""
> db.emp.aggregate(
...     {"$project":{"name":1,"hire_year":{"$year":"$hire_date"}}})
{ "_id" : 0, "name" : "pp", "hire_year" : 2017 }
{ "_id" : 1, "name" : "ww", "hire_year" : 2015 }
{ "_id" : 2, "name" : "ff", "hire_year" : 2013 }
{ "_id" : 3, "name" : "wusir", "hire_year" : 2014 }
{ "_id" : 4, "name" : "peiqi", "hire_year" : 2012 }
{ "_id" : 5, "name" : "eva_jing", "hire_year" : 2011 }
{ "_id" : 6, "name" : "shaowei", "hire_year" : 1900 }
{ "_id" : 7, "name" : "gaylao", "hire_year" : 2010 }
{ "_id" : 8, "name" : "歪歪", "hire_year" : 2015 }
{ "_id" : 9, "name" : "丫丫", "hire_year" : 2010 }
{ "_id" : 10, "name" : "丁丁", "hire_year" : 2011 }
{ "_id" : 11, "name" : "星星", "hire_year" : 2016 }
{ "_id" : 12, "name" : "格格", "hire_year" : 2017 }
{ "_id" : 13, "name" : "张野", "hire_year" : 2016 }
{ "_id" : 14, "name" : "程咬金", "hire_year" : 1997 }
{ "_id" : 15, "name" : "程咬银", "hire_year" : 2013 }
{ "_id" : 16, "name" : "程咬铜", "hire_year" : 2015 }
{ "_id" : 17, "name" : "程咬铁", "hire_year" : 2014 }
"""


# 查看每一个员工工做了多久
db.emp.aggregate(
    {'$project':{'name':1,'hire_period':{
        '$subtract':[
            {'$year':new Date()},
            {'$year':'$hire_date'}
'''
> db.emp.aggregate(
...     {'$project':{'name':1,'hire_period':{
...         '$subtract':[
...             {'$year':new Date()},
...             {'$year':'$hire_date'}
...         ]
...     }}})
{ "_id" : 0, "name" : "pp", "hire_period" : 1 }
{ "_id" : 1, "name" : "ww", "hire_period" : 3 }
{ "_id" : 2, "name" : "ff", "hire_period" : 5 }
{ "_id" : 3, "name" : "wusir", "hire_period" : 4 }
{ "_id" : 4, "name" : "peiqi", "hire_period" : 6 }
{ "_id" : 5, "name" : "eva_jing", "hire_period" : 7 }
{ "_id" : 6, "name" : "shaowei", "hire_period" : 118 }
{ "_id" : 7, "name" : "gaylao", "hire_period" : 8 }
{ "_id" : 8, "name" : "歪歪", "hire_period" : 3 }
{ "_id" : 9, "name" : "丫丫", "hire_period" : 8 }
{ "_id" : 10, "name" : "丁丁", "hire_period" : 7 }
{ "_id" : 11, "name" : "星星", "hire_period" : 2 }
{ "_id" : 12, "name" : "格格", "hire_period" : 1 }
{ "_id" : 13, "name" : "张野", "hire_period" : 2 }
{ "_id" : 14, "name" : "程咬金", "hire_period" : 21 }
{ "_id" : 15, "name" : "程咬银", "hire_period" : 5 }
{ "_id" : 16, "name" : "程咬铜", "hire_period" : 3 }
{ "_id" : 17, "name" : "程咬铁", "hire_period" : 4 }
'''


#四、字符串表达式
# {"$substr":[字符串/$值为字符串的字段名,起始位置,截取几个字节]}
# {"$concat":[expr1,expr2,...,exprN]} #指定的表达式或字符串链接在一块儿返回,只支持字符串拼接
# {"$toLower":expr}
# {"$toUpper":expr

#五、逻辑表达式
# $and
# $or
# $not
# 其余见Mongodb权威指南



#################################################  $group 分组
#        {"$group":{"_id":分组字段,"新的字段名":聚合操做符}}

#一、将分组字段传给$group函数的_id字段便可
{"$group":{"_id":"$sex"}} #按照性别分组
{"$group":{"_id":"$post"}} #按照职位分组
{"$group":{"_id":{"state":"$state","city":"$city"}}} #按照多个字段分组,好比按照州市分组

#二、分组后聚合得结果,相似于sql中聚合函数的聚合操做符:$sum、$avg、$max、$min、$first、$last
#例1:select post,max(salary) from db1.emp group by post;
db.emp.aggregate({"$group":{"_id":"$post","max_salary":{"$max":"$salary"}}})

#例2:去每一个部门最大薪资与最低薪资
db.emp.aggregate({"$group":{"_id":"$post","max_salary":{"$max":"$salary"},"min_salary":{"$min":"$salary"}}})

#例3:若是字段是排序后的,那么$first,$last会颇有用,比用$max和$min效率高
db.emp.aggregate({"$group":{"_id":"$post","first_id":{"$first":"$_id"}}})

#例4:求每一个部门的总工资
db.emp.aggregate({"$group":{"_id":"$post","count":{"$sum":"$salary"}}})

#例5:求每一个部门的人数
db.emp.aggregate({"$group":{"_id":"$post","count":{"$sum":1}}})

#三、数组操做符
{"$addToSet":expr}:不重复
{"$push":expr}:重复
# $addToSet和$push的区别
# 该二者的功能都是给数组添加一个值。可是二者之间有区别,$addToSet要添加的值若是不存在才进行添加操做,可是push只添加一个值;例如:
#
# tags = [“tools”,”garden”]
#
# 若是执行db.collection.update({},{$push:{tag:tools}}) 结果就是 [“tools”,”garden”,“tools”]
#
# 若是执行db.collection.update({},{$addToSet:{tag:tools}}) 结果不变



#例:查询岗位名以及各岗位内的员工姓名:select post,group_concat(name) from db1.emp group by post;
db.emp.aggregate({'$group':{'_id':'$post','names':{'$push':'$name'}}})    # GROUP_CONCAT函数返回一个字符串结果,该结果由分组中的值链接组合而成。

"""
> db.emp.aggregate({'$group':{'_id':'$post','names':{'$push':'$name'}}})
{ "_id" : "sale", "names" : [ "歪歪", "丫丫", "丁丁", "星星", "格格" ] }
{ "_id" : "operation", "names" : [ "张野", "程咬金", "程咬银", "程咬铜", "程咬铁" ] }
{ "_id" : "teacher", "names" : [ "ww", "ff", "wusir", "peiqi", "eva_jing", "shaowei", "gaylao" ] }
{ "_id" : "eat_god", "names" : [ "pp" ] }
"""

db.emp.aggregate({'$group':{'_id':'$post','names':{'$addToSet':'$name'}}})
"""
> db.emp.aggregate({'$group':{'_id':'$post','names':{'$addToSet':'$name'}}})
{ "_id" : "sale", "names" : [ "星星", "丁丁", "格格", "丫丫", "歪歪" ] }
{ "_id" : "operation", "names" : [ "程咬铜", "程咬铁", "程咬金", "程咬银", "张野" ] }
{ "_id" : "teacher", "names" : [ "peiqi", "eva_jing", "shaowei", "wusir", "gaylao", "ff", "ww" ] }
{ "_id" : "eat_god", "names" : [ "pp" ] }
"""



# ##########################################  排序:$sort、限制:$limit、跳过:$skip
{"$sort":{"字段名":1,"字段名":-1}} #1升序,-1降序
{"$limit":n}
{"$skip":n} #跳过多少个文档

# 取平均工资最高的前两个部门
db.emp.aggregate({
    '$group':{'_id':'$post','平均工资':{'$avg':'$salary'}}
},
    {'$sort':{'平均工资':-1}},
    {'$limit':2}
        )

'''
{ "_id" : "teacher", "平均工资" : 151842.90142857144 }
{ "_id" : "operation", "平均工资" : 16800.026 }
'''

#跳过一个
db.emp.aggregate(
    {'$group':{'_id':'$post','平均工资':{'$avg':'$salary'}}},
    {'$sort':{'平均工资':-1}},
    {'$limit':2},
    {'$skip':1}
)
# { "_id" : "operation", "平均工资" : 16800.026 }




# ###########################################  随机  $sample
##集合users包含的文档以下
{ "_id" : 1, "name" : "dave123", "q1" : true, "q2" : true }
{ "_id" : 2, "name" : "dave2", "q1" : false, "q2" : false  }
{ "_id" : 3, "name" : "ahn", "q1" : true, "q2" : true  }
{ "_id" : 4, "name" : "li", "q1" : true, "q2" : false  }
{ "_id" : 5, "name" : "annT", "q1" : false, "q2" : true  }
{ "_id" : 6, "name" : "li", "q1" : true, "q2" : true  }
{ "_id" : 7, "name" : "ty", "q1" : false, "q2" : true  }

#下述操做时从users集合中随机选取3个文档
# db.users.aggregate(
#    [ { $sample: { size: 3 } } ]
# )



#练习: 查询各岗位平均薪资大于10000的岗位名、平均工资,结果按平均薪资降序排列,取前1个
db.emp.aggregate(
    {'$group':{'_id':'$post','平均工资':{'$avg':'$salary'}}},
    {'$match':{'平均工资':{'$gt':10000}}},
    {'$sort':{'平均工资':-1}},
    {'$limit':1}
)
# { "_id" : "teacher", "平均工资" : 151842.90142857144 }
聚合全部相关知识点

 

六:pymongo

官方文档:http://api.mongodb.com/python/current/tutorial.html

from pymongo import MongoClient

#一、连接
client=MongoClient('mongodb://root:123@localhost:27017/')
# client = MongoClient('localhost', 27017)

#二、use 数据库
db=client['db2'] #等同于:client.db1

#三、查看库下全部的集合
print(db.collection_names(include_system_collections=False))

#四、建立集合
table_user=db['userinfo'] #等同于:db.user

#五、插入文档
import datetime
user0={
    "_id":1,
    "name":"ff",
    "birth":datetime.datetime.now(),
    "age":10,
    'hobbies':['music','read','dancing'],
    'addr':{
        'country':'China',
        'city':'BJ'
    }
}

user1={
    "_id":2,
    "name":"pp",
    "birth":datetime.datetime.now(),
    "age":10,
    'hobbies':['music','read','dancing'],
    'addr':{
        'country':'China',
        'city':'weifang'
    }
}
# res=table_user.insert_many([user0,user1]).inserted_ids
# print(res)
# print(table_user.count())

#六、查找

# from pprint import pprint#格式化细
# pprint(table_user.find_one())
# for item in table_user.find():
#     pprint(item)

# print(table_user.find_one({"_id":{"$gte":1},"name":'ff'}))

#七、更新
table_user.update({'_id':1},{'name':'FF'})

#八、传入新的文档替换旧的文档
table_user.save(
    {
        "_id":2,
        "name":'ff_xxx'
    }
)
pymongo

 

七:可视化工具

官方文档:https://robomongo.org/

 




 

知识点本身小结(不完整)

爬虫最经常使用的存储库就是Mongodb。 由于它的存储效率比mysql要高。
lxml这个解析器,容错性要高


MongoDB 是数据库,非关系型数据库。

关系型数据库:若是要存数据,要先设计表结构,每一个字段要有本身的数据类型,而且表之间有关联的要创建关联。

    表与表之间,若是关系创建太多。插入数据或者删除数据的时候,都要先操做被关联表。
        这样两张表,就被强耦合在一块。
        
        盲沟迪比MongeDB和。。。是非关系型数据库。
        不用设计表,就是没有表结构,全都是key:value结构。
        
        特色:
            i. 能让应用层干的事,就让应用层干。
                1) 数据库更精简
                2) 扩展性更强(扩展应用程序永远比扩展数据库要简单的多。)
            ii.  本片文章中那张图
            iii. 不须要建立表。
            iv. 关系型里面的字段 就对应 非关的key
        

    你要管理哪一个库,就要在哪一个库下面建立帐号
    
    use adim # 进入到admin  db
    db.createUser       : 当前的库。
    
    在mongodb里面,没有数据库被和表的命令,只有直接查数据的命令。
    
    
    
    
关于数据库:
    造数据库:
    use  : 
        若有,就进入。  
        若是没有,就建立。
            1:有数据就显示。
            2:没有数据,就不显示。可是已经建立。
            
    增:
        use  db1
    改:
        有表结构的概念,才会有改这个操做。
        在mongodb里面,都没有表这个东西,哪来的表操做
        
    mongodb表的概念其实就是 一个命名空间的概念。
    
    
mongodb类型:
        a. 是基于json类型,又加了几种:
            i. 日期
                1) new Date()  当前时间
            ii. 正则
                1) //
    
    
数据集中在一台机器上  (纵向扩展):
    机器一旦出故障了,你就boomshakalaka了。
        ○ 安全性差
        ○ 计算速度慢

把原本一个数据库应该干的事,分布出去。
可是你们干的仍是一件事。这就减少压力,而且不怕单击boom。

若是两个用户,同时修改同一条数据:
    - 对于mysql来讲,是经过加锁时间的。
    - 在MongoDB如何保证:
        ○ ObjectId
小结
相关文章
相关标签/搜索