爬虫(六)——存储库(一)MongoDB存储库

存储库——MongoDB

一、安装MongoDB 4.0

1、安装

(1)可以去官网下载(我是直接选择msi文件的)

https://www.mongodb.com/download-center

(2)运行文件,可以自定义(custom)安装,注意安装的时候一定要把勾去掉 “Install MongoDB Compass”方便操作,之后一直下一步

安装完成以后,文件目录 如下图

(3)添加安装MongoDB的bin目录到环境变量中

(4)测试,cmd打开控制台,然后输入mongo回车,可以进入MongoDB的shell中,输入show dbs可以看到数据库。表示装成功

2、修改数据库文件和日志保存位置设置(可不改)

MongoDB的数据保存位置和日志位置与其服务的配置文件 mongod.cfg有关,该文档可在 “安装目录in"下找到。里面记录了dbpath(数据库保存位置),logpath(日志文件保存位置),还有连接网络bind_ip等。

这里MongoDB安装在E盘,但是想将数据库和日志文件等保存在其他盘,所以修改dbpath和logpath成自己想要的路径就好

修改完以后要重启服务

net stop MongoDB
net start MongoDB

3、账户管理、远程服务

安装完成后MongoDB默认只能本机访问,并且不需要密码;下面我们添加用户并开启远程服务

(1)打开cmd输入mongo进入MongoDB;进入admin数据库(创建新的数据库)

> use admin

(2)在库中创建用户

db.createUser({
    user: "root", 
    pwd: "123", 
    roles: [
        {role: "root",db: "admin"}
    ]
})
# 亦可以一个用户对多个数据库管理
角色类型 权限级别
普通用户角色 read、readWrite
数据库管理员角色 dbAdmin、dbOwner、userAdmin
集群管理员角色 clusterAdmin、clusterManager、clusterMonitor、hostManager
数据库备份与恢复角色 backup、restore
所有数据库角色 readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
超级用户角色 root
核心角色 __system

(3)修改允许远程连接

修改默认配置文件bin/mongod.cfg中的bingIp中127.0.0.10.0.0.0,这里可以实现其他网段地址的连接;(千万不要将这句注释,否则服务可能无法启动)

#security:的注释去掉,然后添加authorization: enabled注意authorization前面要有两个空格

(4)重启数据库

net stop MongoDB   
net start MongoDB

(5)测试

如果测试结果如下,则表示用户设置成功

# 登录方式一
mongo 127.0.0.1:27017/admin(数据库名字) -u root(用户名) -p 123(密码)

# 登录方式二
> mongo
> use test
>db.auth("sb","sb123")           # 必须要用双引号

# 登录方式三
mongo --port 27017 -u "root" -p "123" --authenticationDatabase "admin"

三、MongoDB数据库操作

1、对库操作

# 1.增加数据库
use 数据库名      # 存在则切换到该数据库,不存在则新建数据库

# 2.查看数据库
show dbs

# 3.删除数据库
use test 	# 先切换到要删的库下
db.dropDatabase()	 # 删除当前库

# 帮助查看所有库相关操作-- db.help()
db.help()

2、对集合操作——类似表

use test  # 先切换到数据库下

# 1.新增集合
db.user    # 创建user表

# 2.查看集合
show tables
# 或者 show colletions

# 3.删除集合
db.user.drop()

# 帮助查看所有集合相关操作-- db.(集合名).help()
db.user.help()

3、对文档操作—— 类似记录

MongoDB中存储的文档必须有一个"_id"键。这个键的值可以是任意类型,默认是个ObjectId对象。
在一个集合里,每个文档都有唯一的“_id”,确保集合里每个文档都能被唯一标识。
不同集合"_id"的值可以重复,但同一集合内"_id"的值必须唯一
ObjectId是"_id"的默认类型,ObjectId采用12字节的存储空间,是一个由24个十六进制数字组成的字符串
    0|1|2|3|   4|5|6|     7|8    9|10|11    
    时间戳      机器      PID    计数器

如果插入文档时没有"_id"键,系统会自帮你创建 一个

(1)增加文档—— insert()

use test  # 先切换到数据库下

db.user.insert({'_id':1,'name':'tom'})     # id要用_id作为key
# 或者数据量较大时使用变量:
user0={
    "name":"egon",
    "age":10,
    'hobbies':['music','read','dancing'],
    'addr':{
        'country':'China',
        'city':'BJ'
    }
}

db.test.insert(user0)

# 插入多条数据  ---- insertMany([...])
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'
    }
}

db.user.insertMany([user1,user2])
# save() 方法
use test
db.save({'_id':1,'name':'tom'})    # 有相同的id,则覆盖原数据;没有该id,则新增数据
db.save({'a':123})     # 不指定id,和新增数据相同

(2)查看文档—— find()

use test

# 1.查找所有
db.user.find()

# 按条件查询
#(1)比较运算
!=  ----    {'$ne':3}   # 不等于3
>   -----    {'$gt':2}  # 大于2
<    ----    {'$lt':2}   # 小于2
>=   ----    {'$gte':4}   # 大于等于
>=   ----    {'$lte':4}   # 小于等于

db.user.find({'_id':3})
db.user.find({'_id':{'$ne':3}})    # id不等于3
db.user.find({'name':{'$ne':'Tom'}})    # 名字不是Tom


# (2)逻辑运算   and   not    or
and ----- {'$and':[....]}
not ----- {'$not':...}
or ----- {'$or':[....]}

# id>=2 and id<=4
db.user.find({'_id':{"$gte":2,"$lt":4}})

# id >= 2 and age < 40;
db.user.find({"_id":{"$gte":2},"age":{"$lt":40}})
# 或者
db.user.find({
    '$and':[
        {"_id":{"$gte":2}},
        {"age":{"$lt":40}}
    ]
})

# id >= 5 or name = "alex";
db.user.find({
    "$or":[
        {'_id':{"$gte":5}},
        {"name":"alex"}
     ]
})

# id % 2=1    id取模2等于1
db.user.find({'_id':{"$mod":[2,1]}})

# 取反  取id为奇数
db.user.find({'_id':{
    '$not':{
        '$mod':[2,0]
    }
}})


# (3)成员运算  in,not in
in   -----   {'$in':[....]}
not in -------{'$nin':[]}

db.user.find({'name':{'$in':['ton','eton']}})


# (4)正则匹配  regexp
regexp -----  /正则表达/i
    i 忽略大小写
    m 多行匹配模式
    x 忽略非转义的空白字符
    s 单行匹配模式

db.user.find({'name':/^T.*?(g|n)/i})


# (5)查询指定字段
1  ---  表示需要
0  ----  不需要,默认

# 只要name,age
db.user.find(
    {'name':'Tom'},
    {'name':1,
     'age':1,
     '_id':0
    }
)


# (6)查询数组
既有... 又有...     -----    {'$all':[...,...]}
第n个     ----    key.n
要n个    -----    {'$slice':n}   # -n表示后n个
A下的B是C   -----    {'A.B':C}

# 查看有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})


# (7)排序
sort()
1   -----   升序
-1  -----   降序
# 排序:--1代表升序,-1代表降序
db.user.find().sort({"name":1,})
db.user.find().sort({"age":-1,'_id':1})


# (8)分页
limit   -----   取几个
skip   ------   跳过几个再开始取

# 跳过两个以后,取一个
db.user.find().limit(1).skip(2)


# (9)获取数量
count()

db.user.count({'age':{'$gte':20}})


# (10)key的值为null或者没有这个key
db.t2.find({'b':null})

(3)修改文档——update()

update() 方法用于更新已存在的文档。语法格式如下:
db.collection.update(
   <query>,   # 查询条件,条件为空,表示所有文档
   <update>,
   {
     upsert: <boolean>, # 默认为false,代表如果不存在update的记录不更新也不插入,设置为true代表插入
     multi: <boolean>,   # 默认为false,代表只更新找到的第一条记录,设为true,代表更新找到的全部记录
     writeConcern: <document>
   }
)
参数说明:对比update db1.t1 set name='EGON',sex='Male' where name='egon' and age=18;

# 1.覆盖式修改
db.user.update({
    {'name':'tom'},
    {'sex':'male','phone':'123123'}
})

# 2.局部修改 ----  {'$set':{修改的数据}}
db.user.update({
    {'name':'tom'},
    {'$set':{'sex':'male','phone':'123123'}}
})

# 3.批量修改
db.user.update({
    {'name':'tom'},
    {'$set':{'sex':'male','phone':'123123'}},
    {'multi':True}
})

# 4.有则修改,无则新增
db.user.update({
    {'name':'tom'},
    {'$set':{'sex':'male','phone':'123123'}},
    {'multi':True,
     'upsert':True
    }
})

# 5.嵌套数据修改 ----   “ . ”号
# 城市的国家修改,第二个爱好修改
db.user.update({
    {},
    {'$set':{'city.country':'China','hobbies.1':'eat'}},
    {'multi':True,
     'upsert':True
    }
})
# 增加1  ------  {'$inc'}
db.user.update(
    {},
    {
        "$inc":{"age":1}
    },
    {
        "multi":true
    }
)
# 添加删除数组内元素   ----    $push  $pop    $pull
# 1.增加爱好
db.user.update({"name":"yuanhao"},{"$push":{"hobbies":"read"}})

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

# 3.删除数组元素  ---- $pop()  两头删
-1    ----   从头开始删1个
1     -----   从末尾开始删1一个
db.user.update(
    {"name":"yuanhao"},
    {"$pop":{"hobbies":1}}
)

# 4.按照条件删    -----  pull() 根据条件删
# 删除所有人的read爱好
db.user.update(
    {'addr.country':"China"},
    {"$pull":{"hobbies":"read"}},
	{
	    "multi":true
	}
)

(4)删除文档——deleteOne() / deleteMany()

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

# 2、删除国家为China的全部
db.user.deleteMany( {'addr.country': 'China'} ) 

# 3、删除全部
db.user.deleteMany({}) 

四、MongoDB基本数据类型

MongoDB在保留了JSON基本键/值对特性的基础上,添加了其他一些数据类型。在不同的编程语言下,这些类型的确切表示有些许差异。

# 1、null:用于表示空或不存在的字段
d={'x':null}

# 2、布尔型:true和false
d={'x':true,'y':false}

# 3、数值
d={'x':3,'y':3.1415926}

# 4、字符串
d={'x':'egon'}

# 5、日期
d={'x':new Date()}
d.x.getHours()

# 6、正则表达式
d={'pattern':/^egon.*?nb$/i}

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

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

# 8、内嵌文档
user={'name':'egon','addr':{'country':'China','city':'YT'}}
user.addr.country

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

五、聚合

1、筛选—— $match

aggregate()
$match    # 条件,和where,having类似
$group    # 分组,和group by类似
$字段名  # 表示取该字段的值

# 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"}}},  # 这个_id表示分组依据
    {"$match":{"avg_salary":{"$gt":10000}}}
)


2、投射—— $project

  • 将一些字段不需要的去掉,额外需要的新增
  • 投射既可以在起始时使用,也可以在中间使用
{"$project":{"要保留的字段名":1,"要去掉的字段名":0,"新增的字段名":"表达式"}}

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


# 表达式之日期表式:
{"$year":"$date"}
{"$month":"$date"}
{"$week":"$date"}
{"$dayOfMonth":"$date"}
{"$dayOfWeek":"$date"}
{"$dayOfYear":"$date"}
{"$hour":"$date"}
{"$minute":"$date"}
{"$second":"$date"}

# 获取员工的名字和工作年限
db.emp.aggregate(
    {"$project":{"name":1,"hire_year":{"$year":"$hire_date"}}}
)


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

# 所有人的名字变大写
db.emp.aggregate(
    {"$project":{'new_name':{'$toUpper':'$name'}}}
)

# 投射示例
# 获取员工的name、post、目前年龄
db.emp.aggregate(
    {"$project":{
        "name":1,
        "post":1,
        "new_age":{"$add":["$age",1]}
        }
})

3、分组—— $group

{"$group":{"_id":分组字段,"新的字段名":聚合操作符}}    # 这里的_id表示根据什么分组


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

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


4、排序— $sort,限制— $limit,跳过— $skip

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

# 取平均工资最高的前两个部门,先按平均公司排序,若工资一样再按id排序
db.emp.aggregate(
    {
        "$group":{"_id":"$post","平均工资":{"$avg":"$salary"}}
    },
    {
        "$sort":{"平均工资":-1, "_id":1}
    },
    {
        "$limit":2
    }
)

六、随机取几个数据

$sample

# 随机取3个文档
db.users.aggregate(
   [ { $sample: { size: 3 } } ]
)

七、可视化工具

链接:https://robomongo.org/

八、python中操作MongoDB

from pymongo import MongoClient  # pip3 install pymongo

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

# 2、use 数据库,切换到库
db=client['db2'] 	# 等同于:client.db1
# print(db.collection_names())

# 3、查看库下所有的集合
print(db.collection_names(include_system_collections=False))

# 4、创建集合,切换到表
table_user=db['userinfo'] `# 等同于:db.user

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

user1={
    "_id":2,
    "name":"alex",
    "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())

# 6、查找
# 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":'egon'}))

# 7、更新
table_user.update({'_id':1},{'name':'EGON'})
 
# 8、传入新的文档替换旧的文档
table_user.save(
    {
        "_id":2,
        "name":'egon_xxx'
    }
)

原文地址:https://www.cnblogs.com/linagcheng/p/10831443.html