沭阳学爬虫10高效存储MongoDB

10高效存储MongoDB

当我们成功提取了数据之后,该往哪里存放呢?

用文本文件当然是可以的,但文本存储不方便检索

有没有既方便存,又方便检索的存储方式呢?——MongoDB

MongoDB是由C++语言编写的非关系型数据库

是一个基于分布式文件存储的开源数据库系统

其内容存储形式类似JSON对象,它的字段值可以包含其他文档、数组、文档数组

为什么不用MySQL?

mysql对于一些结构化或嵌套类型的数据存储不太方便,而且需要额外维护字段信息,相对麻烦

MongoDB适合存储这类数据

准备工作

开始之前,请确保你已经安装好了MongoDB并启动了其服务,同时安装好了Python的PyMongo库

MongoDB安装教程:https://www.cnblogs.com/TM0831/p/10606624.html

安装好之后,我们需要把MongoDB服务启动起来

image-20210218141547814

  • 注意:这里我们为了学习,仅使用MongoDB最基本的单机版,MongoDB还有主从复制、副本集、分片集群架构,可用性可靠性更好,如有需要可以自行搭建相应的集群进行使用

启动完成之后,它会默认在本地localhost的27017端口上运行

接下来我们需要安装PyMongo库,它是Python用来操作MongoDB的第三方库

pip install pymongo

连接MongoDB

连接MongoDB时,我们需要使用PyMongo库里面的MongoClient

一般来说,我们需要向其传入MongoDB的IP及端口

其中第一个参数为地址host,第二个参数为端口port(默认27017)

import pymongo
client = pymongo.MongoClient(host='localhost',port=27017)

这样就可以创建MongoDB的连接对象了

MongoClient的第一个参数host还可以直接传入MongoDB的连接字符串,它以mongodb开头

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

也可以达到同样的连接效果

指定数据库

MongoDB中可以建立多个数据库

我们需要指定操作其中一个数据库,以test数据库作为指定使用的例子

db = client.test

这里调用client的test属性即可返回test数据库

还有一种等价的指定方式

db = client['test']

指定集合

MongoDB的每个数据库中包含了许多集合**(collection)**

它们类似于关系型数据库(mysql、SQL Server…)中的表

我们指定一个名称为students的集合,与指定数据库类似,指定集合也有两种方式

collection = db.students

或者

collection = db['students']

这样我们便声明了一个Collection对象

插入数据

我们对students这个集合新建一条学生数据,这条数据以字典形式表示

student = {
    'id': '20170101',
    'name': 'Jordan',
    'age': 20,
    'gender': 'male'
}

数据制定了学生的学好、姓名、年龄和性别。

接下来,我们直接调用 collection的insert方法即可插入数据

result = collection.insert(student)
print(result)

image-20210218164834156

在MongoDB中,每条数据其实都有一个_id属性来唯一标识

如果没有显式(清楚且明确的指定了实现内容) 指明该属性,MongoDB会自动产生一个ObjectId类型的_id属性

insert()方法会在执行后返回_id值


我们也可以同时插入多条数据,只需要以列表形式传递即可

student1 = {
    'id': '20170102',
    'name': 'Leon',
    'age': 22,
    'gender': 'male'
}

student2 = {
    'id': '20170203',
    'name': 'Mike',
    'age': 21,
    'gender': 'male'
}
result = collection.insert([student1,student2])
print(result)

image-20210218170700817

返回结果是对应的_id的集合

DeprecationWarning: insert is deprecated. Use insert_one or insert_many instead

实际上,在PyMongo中,官方已经不推荐使用insert方法了

目前官方推进使用insert_one 和 insert_many方法来分别插入单条记录和多条记录

student = {
    'id': '20170204',
    'name': 'Tom',
    'age': 25,
    'gender': 'male'
}

result = collection.insert_one(student)
print(result)
print(result.inserted_id)

image-20210218171421661

与insert方法不同,这次返回的是InsertOneResult对象

我们可以调用其inserted_id属性获取_id


对于insert_many方法,我们可以将数据以列表形式传递

student1 = {
    'id': '20170105',
    'name': 'Jack',
    'age': 20,
    'gender': 'male'
}

student2 = {
    'id': '20170206',
    'name': 'Xiaoming',
    'age': 21,
    'gender': 'male'
}

result = collection.insert_many([student1,student2])
print(result)
print(result.inserted_ids)

image-20210218172036966

该方法返回的类型是InsertManyResult,调用inserted_ids属性可以获取插入数据的_id列表


查询

插入数据后,我们可以利用find_one或find方法进行查询

  • find_one查询得到的是单个结果
  • find则返回一个生成器对象
result = collection.find_one({'name':'Leon'})
print(type(result))
print(result)

image-20210218172821272

我们查询name为Leon的数据,它的返回结果是字典类型

可以发现,它多了_id属性,这就是MongoDB在插入过程中自动添加的

我们还可以根据ObjectId来查询,此时需要调用bson库里面的objectid

from bson.objectid import ObjectId

result = collection.find_one({'_id':ObjectId('602e2e28df03b698a534a0b2')})

image-20210218174012009

如果查询结果不存在,则会返回None

对于多条数据的查询,我们可以使用find方法。

例如,查找年龄为20的数据

results = collection.find({'age':20})
print(results)
for result in results:
    print(result)

image-20210218174820657

返回Cursor类型,它相当于一个生成器,我们需要遍历获取的所有结果,其中每个结果都是字典类型

查询年龄大于20的数据

results = collection.find({'age':{'$gt':20}})

image-20210218175033609

这里查询条件的键值已经不是单纯的数字了,而是一个字典,其键名为比较符号**$gt**,意思是大于,键值为20

比较符号归纳如下

还可以进行正则匹配查询,例如,查询名字以M开头的学生数据

results = collection.find({'name':{'$regex':'^M.*'}})

image-20210218211353256

使用$regex来指定正则匹配,^M.*代表以M开头的正则表达式

功能符号归类如下

这些操作的更详细用法,参考https://docs.mongodb.com/manual/reference/operator/query/

计数

要统计查询结果有多少条数据,可以调用count方法

我们统计所有数据条数

count = collection.find().count()
print(count)

image-20210219072256820

还可以统计符合某个条件的数据

count = collection.find({'age':21}).count()
print(count)

image-20210219072431449

排序

可以调用sort方法,并在其中传入排序的字段及升降序标志

results = collection.find().sort('name',pymongo.ASCENDING)
print([result['name']for result in results])

image-20210219072840525

这里我们调用pymongo.ASCENDING指定升序,如果要降序排列,可以传入pymongo.DESCENDING

偏移

某些情况下,我们可能只需要取某几个元素,利用skip方法偏移几个位置,比如偏移2,就代表忽略前两个元素,得到第3个及以后的元素

results = collection.find().sort('name',pymongo.ASCENDING).skip(2)
print([result['name']for result in results])

image-20210219091051674

我们还可以用limit方法指定要取的结果个数

results = collection.find().sort('name',pymongo.ASCENDING).skip(2).limit(2)
print([result['name']for result in results])

image-20210219091309154

加了limit方法,限制之后,就会截取两个结果返回

  • 值得注意的是,在数据量非常庞大的时候,比如在查询千万、亿级别的数据库时,最好不要使用大的偏移量,这样很可能导致内存溢出

  • 此时可以使用如下操作来查询

    from bson.objectid import ObjectId

    collection.find({'_id:{'$gt':ObjectId('602e2e28df03b698a534a0b2')}'})

这时需要记录好上次查询的_id

更新

对于数据更新,我们可以使用update方法,指定更新的条件和更新后的数据即可

condition = {'name':'Mike'}
student = collection.find_one(condition)
student['age']= 25
result = collection.update(condition,student)
print(result)

我们要更新name为Mike的数据的年龄:首先指定查询条件,然后将数据查询出来,修改年龄后调用update方法将原条件和修改后的数据传入

image-20210219092748343

返回结果是字典形式,ok代表执行成功,nModified代表影响的数据条数


我们也可以使用**$set操作符**对数据进行更新

result = collection.update(condition,{'$set':student})

这样可以只更新student字典内存在的字段

如果原先还有其他字段,则不会更新,也不会删除

而如果不用$set的话,则会把之前的数据全部用student字典替换

如果原本存在其他字段,则会被删除


另外,update方法也是官方不推荐使用的方法。推荐使用update_one和update_many方法

用法更加严格,它们的第2个参数需要使用$类型操作符作为字典的键名

condition = {'name':'Mike'}
student = collection.find_one(condition)
student['age'] = 26
result = collection.update_one(condition,{'$set':student})
print(result)
print(result.matched_count,result.modified_count)

image-20210219094032415

调用update_one方法,使得第2个参数不能再直接传入修改后的字典,而是需要使用{’$set’:student}这样的形式

其返回结果是UpdateResult类型。然后分别调用matched_count和modified_count属性,可以获得匹配的数据条数和影响的数据条数

再看一个例子

condition = {'age':{'$gt':20}}
result = collection.update_one(condition,{'$inc':{'age':1}})
print(result)
print(result.matched_count,result.modified_count)

这里指定查询条件为年龄大于20,然后更新条件为

{’$inc’:{‘age’:1}},表示年龄加1,执行之后会将第一条符合条件的数据年龄加1

image-20210219094914808

匹配条数为1条,影响条数也为1条

如果调用update_many方法,则会将所有符合条件的数据都更新

condition = {'age':{'$gt':20}}
result = collection.update_many(condition,{'$inc':{'age':1}})
print(result)
print(result.matched_count,result.modified_count)

image-20210219095039910

这时所有匹配到的数据都会被更新

删除

删除操作比较简单,直接调用remove方法指定删除的条件即可,此时符合条件的数据均会被删除

result = collection.remove({'name':'Mike'})
print(result)

image-20210219095618680

这里官方依然推荐两个新方法——delete_one、delete_many

result = collection.delete_one({'name':'Xiaoming'})
print(result)
print(result.deleted_count)
result = collection.delete_many({'age':{'$gt':25}})
print(result.deleted_count)

image-20210219100047949

delete_one即删除第一个符合条件的数据,delete_many即删除所有符合条件的数据

它们返回结果都是DeleteResult类型,可以调用deleted_count属性获取删除的数据条数

其他操作

PyMongo还提供了一些组合方法

  • find_one_and_delete 查找后删除

  • find_one_and_replace 查找后替换

  • find_one_and_update 查找后更新

还可以对索引进行操作

create_index 、 create_indexes 、drop_index等

PyMongo还提供了一些组合方法

  • find_one_and_delete 查找后删除

  • find_one_and_replace 查找后替换

  • find_one_and_update 查找后更新

还可以对索引进行操作

create_index 、 create_indexes 、drop_index等

PyMongo的详细用法,参见官方文档http://api.mongodb.com/python/current/api/pymongo/collection.html

数据库和集合本身的操作,参见官方文档http://api.mongodb.com/python/current/api/pymongo/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值