python 读取csv文件导入mongodb_python使用pymongo访问MongoDB的基本操作,以及CSV文件导出...

1. 环境。

Python:3.6.1

Python IDE:pycharm

系统:win7

2. 简单示例

import pymongo

# mongodb服务的地址和端口号

mongo_url = "127.0.0.1:27017"

# 连接到mongodb,如果参数不填,默认为“localhost:27017”

client = pymongo.MongoClient(mongo_url)

#连接到数据库myDatabase

DATABASE = "myDatabase"

db = client[DATABASE]

#连接到集合(表):myDatabase.myCollection

COLLECTION = "myCollection"

db_coll = db[COLLECTION ]

# 在表myCollection中寻找date字段等于2017-08-29的记录,并将结果按照age从大到小排序

queryArgs = {'date':'2017-08-29'}

search_res = db_coll.find(queryArgs).sort('age',-1)

for record in search_res:

print(f"_id = {record['_id']}, name = {record['name']}, age = {record['age']}")

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

3. 要点

针对读操作,进行数据统计,尽量使用多线程,节省时间,只是要注意线程数量,会大量吃内存。

4. mongoDB的数据类型

MongoDB支持许多数据类型,如下:

字符串 - 用于存储数据的最常用的数据类型。MongoDB中的字符串必须为UTF-8。

整型 - 用于存储数值。 整数可以是32位或64位,具体取决于服务器。

布尔类型 - 用于存储布尔值(true / false)值。

双精度浮点数 - 用于存储浮点值。

最小/最大键 - 用于将值与最小和最大BSON元素进行比较。

数组 - 用于将数组或列表或多个值存储到一个键中。

时间戳 - ctimestamp,当文档被修改或添加时,可以方便地进行录制。

对象 - 用于嵌入式文档。

对象 - 用于嵌入式文档。

Null - 用于存储Null值。

符号 - 该数据类型与字符串相同; 但是,通常保留用于使用特定符号类型的语言。

日期 - 用于以UNIX时间格式存储当前日期或时间。您可以通过创建日期对象并将日,月,年的 - 日期进行指定自己需要的日期时间。

对象ID - 用于存储文档的ID。

二进制数据 - 用于存储二进制数据。

代码 - 用于将JavaScript代码存储到文档中。

正则表达式 - 用于存储正则表达式。

不支持的数据类型:

python中的集合(set)

5. 对表(集合collection)的操作

import pymongo

# mongodb服务的地址和端口号

mongo_url = "127.0.0.1:27017"

# 连接到mongodb,如果参数不填,默认为“localhost:27017”

client = pymongo.MongoClient(mongo_url)

#连接到数据库myDatabase

DATABASE = "amazon"

db = client[DATABASE]

#连接到集合(表):myDatabase.myCollection

COLLECTION = "galance20170801"

db_coll = db[COLLECTION]

1

2

3

4

5

6

7

8

9

10

11

12

13

14

5.1. 查找记录:find

(5.1.1)指定返回哪些字段

# 示例一:所有字段

# select * from galance20170801

searchRes = db_coll.find()

# 或者searchRes = db_coll.find({})

1

2

3

4

# 示例二:用字典指定要显示的哪几个字段

# select _id,key from galance20170801

queryArgs = {}

projectionFields = {'_id':True, 'key':True} # 用字典指定

searchRes = db_coll.find(queryArgs, projection = projectionFields)

# 结果{'_id': 'B01EYCLJ04', 'key': 'pro audio'}

1

2

3

4

5

6

# 示例三:用字典指定去掉哪些字段

queryArgs = {}

projectionFields = {'_id':False, 'key':False} # 用字典指定

searchRes = db_coll.find(queryArgs, projection = projectionFields)

# 结果{'activity': False, 'avgStar': 4.3, 'color': 'Yellow & Black', 'date': '2017-08-01'}

1

2

3

4

5

# 示例四:用列表指定要显示哪几个字段

# select _id,key,date from galance20170801

queryArgs = {}

projectionFields = ['key','date'] # 用列表指定,结果中一定会返回_id这个字段

searchRes = db_coll.find(queryArgs, projection = projectionFields)

# 结果{'_id': 'B01EYCLJ04', 'date': '2017-08-01', 'key': 'pro audio'}

1

2

3

4

5

6

(5.1.2)指定查询条件

(5.1.2.1). 比较:=,!=,>, <, >=, <=

$ne:不等于(not equal)

$gt:大于(greater than)

$lt:小于(less than)

$lte:小于等于(less than equal)

$gte:大于等于(greater than equal)

1

2

3

4

5

# 示例一:相等

# select _id,key,sales,date from galance20170801 where key = 'TV & Video'

queryArgs = {'key':'TV & Video'}

projectionFields = ['key','sales','date']

searchRes = db_coll.find(queryArgs, projection = projectionFields)

# 结果:{'_id': '0750699973', 'date': '2017-08-01', 'key': 'TV & Video', 'sales': 0}

1

2

3

4

5

6

# 示例二:不相等

# select _id,key,sales,date from galance20170801 where sales != 0

queryArgs = {'sales':{'$ne':0}}

projectionFields = ['key','sales','date']

searchRes = db_coll.find(queryArgs, projection = projectionFields)

# 结果:{'_id': 'B01M996469', 'date': '2017-08-01', 'key': 'stereos', 'sales': 2}

1

2

3

4

5

6

# 示例三:大于

# where sales > 100

queryArgs = {'sales':{'$gt':100}}

# 结果:{'_id': 'B010OYASRG', 'date': '2017-08-01', 'key': 'Sound Bar', 'sales': 124}

1

2

3

4

# 示例四:小于

# where sales < 100

queryArgs = {'sales':{'$lt':100}}

# 结果:{'_id': 'B011798DKQ', 'date': '2017-08-01', 'key': 'pro audio', 'sales': 0}

1

2

3

4

# 示例五:指定范围

# where sales > 50 and sales < 100

queryArgs = {'sales':{'$gt':50, '$lt':100}}

# 结果:{'_id': 'B008D2IHES', 'date': '2017-08-01', 'key': 'Sound Bar', 'sales': 66}

1

2

3

4

# 示例六:指定范围,大于等于,小于等于

# where sales >= 50 and sales <= 100

queryArgs = {'sales':{'$gte':50, '$lte':100}}

# 结果:{'_id': 'B01M6DHW26', 'date': '2017-08-01', 'key': 'radios', 'sales': 50}

1

2

3

4

(5.1.2.2). and

# 示例一:不同字段,并列条件

# where date = '2017-08-01' and sales = 100

queryArgs = {'date':'2017-08-01', 'sales':100}

# 结果:{'_id': 'B01BW2YYYC', 'date': '2017-08-01', 'key': 'Video', 'sales': 100}

1

2

3

4

# 示例二:相同字段,并列条件

# where sales >= 50 and sales <= 100

# 正确:queryArgs = {'sales':{'$gte':50, '$lte':100}}

# 错误:queryArgs = {'sales':{'$gt':50}, 'sales':{'$lt':100}}

# 结果:{'_id': 'B01M6DHW26', 'date': '2017-08-01', 'key': 'radios', 'sales': 50}

1

2

3

4

5

(5.1.2.3). or

# 示例一:不同字段,或条件

# where date = '2017-08-01' or sales = 100

queryArgs = {'$or':[{'date':'2017-08-01'}, {'sales':100}]}

# 结果:{'_id': 'B01EYCLJ04', 'date': '2017-08-01', 'key': 'pro audio', 'sales': 0}

1

2

3

4

# 示例二:相同字段,或条件

# where sales = 100 or sales = 120

queryArgs = {'$or':[{'sales':100}, {'sales':120}]}

# 结果:

# {'_id': 'B00X5RV14Y', 'date': '2017-08-01', 'key': 'Chargers', 'sales': 120}

# {'_id': 'B0728GGX6Y', 'date': '2017-08-01', 'key': 'Glasses', 'sales': 100}

1

2

3

4

5

6

(5.1.2.4). in,not in,all

# 示例一:in

# where sales in (100,120)

# 这个地方一定要注意,不能用List,只能用元组,因为是不可变的

# 如果用了 {'$in': [100,120]},就会出现异常:TypeError: unhashable type: 'list'

queryArgs = {'sales':{'$in': (100,120)}}

# 结果:

# {'_id': 'B00X5RV14Y', 'date': '2017-08-01', 'key': 'Chargers', 'sales': 120}

# {'_id': 'B0728GGX6Y', 'date': '2017-08-01', 'key': 'Glasses', 'sales': 100}

1

2

3

4

5

6

7

8

# 示例二:not in

# where sales not in (100,120)

queryArgs = {'sales':{'$nin':(100,120)}}

# 结果:{'_id': 'B01EYCLJ04', 'date': '2017-08-01', 'key': 'pro audio', 'sales': 0}

1

2

3

4

# 示例三:匹配条件内所有值 all

# where sales = 100 and sales = 120

queryArgs = {'sales':{'$all':[100,120]}} # 必须同时满足

# 结果:无结果

1

2

3

4

# 示例四:匹配条件内所有值 all

# where sales = 100 and sales = 100

queryArgs = {'sales':{'$all':[100,100]}} # 必须同时满足

# 结果:{'_id': 'B01BW2YYYC', 'date': '2017-08-01', 'key': 'Video', 'sales': 100}

1

2

3

4

(5.1.2.5). 字段是否存在

# 示例一:字段不存在

# where rank2 is null

queryArgs = {'rank2':None}

projectionFields = ['key','sales','date', 'rank2']

searchRes = db_coll.find(queryArgs, projection = projectionFields)

# 结果:{'_id': 'B00ACOKQTY', 'date': '2017-08-01', 'key': '3D TVs', 'sales': 0}

# mongodb中的命令

db.categoryAsinSrc.find({'isClawered': true, 'avgCost': {$exists: false}})

1

2

3

4

5

6

7

8

9

# 示例二:字段存在

# where rank2 is not null

queryArgs = {'rank2':{'$ne':None}}

projectionFields = ['key','sales','date','rank2']

searchRes = db_coll.find(queryArgs, projection = projectionFields).limit(100)

# 结果:{'_id': 'B014I8SX4Y', 'date': '2017-08-01', 'key': '3D TVs', 'rank2': 4.0, 'sales': 0}

1

2

3

4

5

6

(5.1.2.6). 正则表达式匹配:$regex(SQL:like)

# 示例一:关键字key包含audio子串

# where key like "%audio%"

queryArgs = {'key':{'$regex':'.*audio.*'}}

# 结果:{'_id': 'B01M19FGTZ', 'date': '2017-08-01', 'key': 'pro audio', 'sales': 1}

1

2

3

4

(5.1.2.7). 数组中必须包含元素:$all

# 查询记录,linkNameLst是一个数组,指定linkNameLst字段必须包含 'Electronics, Computers & Office' 这个元素。

db.getCollection("2018-01-24").find({'linkNameLst': {'$all': ['Electronics, Computers & Office']}})

# 查询记录,linkNameLst是一个数组,指定linkNameLst字段必须同时包含 'Wearable Technology' 和 'Electronics, Computers & Office' 这两个元素。

db.getCollection("2018-01-24").find({'linkNameLst': {'$all': ['Wearable Technology', 'Electronics, Computers & Office']}})

1

2

3

4

5

(5.1.2.8). 按数组大小查询

两个思路:

第一个思路:使用$where(具有很大的灵活性,但是速度会慢一些)

# priceLst是一个数组, 目标是查询 len(priceLst) < 3

db.getCollection("20180306").find({$where: "this.priceLst.length < 3"})

1

2

关于$where,请参考官方文档:http://docs.mongodb.org/manual/reference/operator/query/where/。

第二个思路:判断数组中的某个指定索引的元素是否存在(会比较高效)

例如:如果要求 len(priceLst) < 3:就意味着 num[ 2 ]不存在

# priceLst是一个数组, 目标是查询 len(priceLst) < 3

db.getCollection("20180306").find({'priceLst.2': {$exists: 0}})

1

2

例如:如果要求 len(priceLst) > 3:就意味着 num[ 3 ]存在

# priceLst是一个数组, 目标是查询 len(priceLst) > 3

db.getCollection("20180306").find({'priceLst.3': {$exists: 1}})

1

2

(5.1.3)指定查询条件

(5.1.3.1). 限定数量:limit

# 示例一:按sales降序排列,取前100

# select top 100 _id,key,sales form galance20170801 where key = 'speakers' order by sales desc

queryArgs = {'key':'speakers'}

projectionFields = ['key','sales']

searchRes = db_coll.find(queryArgs, projection = projectionFields)

topSearchRes = searchRes.sort('sales',pymongo.DESCENDING).limit(100)

1

2

3

4

5

6

(5.1.3.2). 排序:sort

# 示例二:按sales降序,rank升序

# select _id,key,date,rank from galance20170801 where key = 'speakers' order by sales desc,rank

queryArgs = {'key':'speakers'}

projectionFields = ['key','sales','rank']

searchRes = db_coll.find(queryArgs, projection = projectionFields)

# sortedSearchRes = searchRes.sort('sales',pymongo.DESCENDING) # 单个字段

sortedSearchRes = searchRes.sort([('sales', pymongo.DESCENDING),('rank', pymongo.ASCENDING)]) # 多个字段

# 结果:

# {'_id': 'B000289DC6', 'key': 'speakers', 'rank': 3.0, 'sales': 120}

# {'_id': 'B001VRJ5D4', 'key': 'speakers', 'rank': 5.0, 'sales': 120}

1

2

3

4

5

6

7

8

9

10

(5.1.3.3). 统计:count

# 示例三:统计匹配记录总数

# select count(*) from galance20170801 where key = 'speakers'

queryArgs = {'key':'speakers'}

searchResNum = db_coll.find(queryArgs).count()

# 结果:

# 106

1

2

3

4

5

6

5.2. 添加记录

5.2.1. 单条插入

# 示例一:指定 _id,如果重复,会产生异常

ID = 'firstRecord'

insertDate = '2017-08-28'

count = 10

insert_record = {'_id':ID, 'endDate': insertDate, 'count': count}

insert_res = db_coll.insert_one(insert_record)

print(f"insert_id={insert_res.inserted_id}: {insert_record}")

# 结果:insert_id=firstRecord: {'_id': 'firstRecord', 'endDate': '2017-08-28', 'count': 10}

1

2

3

4

5

6

7

8

# 示例二:不指定 _id,自动生成

insertDate = '2017-10-10'

count = 20

insert_record = {'endDate': insertDate, 'count': count}

insert_res = db_coll.insert_one(insert_record)

print(f"insert_id={insert_res.inserted_id}: {insert_record}")

# 结果:insert_id=59ad356d51ad3e2314c0d3b2: {'endDate': '2017-10-10', 'count': 20, '_id': ObjectId('59ad356d51ad3e2314c0d3b2')}

1

2

3

4

5

6

7

5.2.2. 批量插入

# 更高效,但要注意如果指定_id,一定不能重复

# ordered = True,遇到错误 break, 并且抛出异常

# ordered = False,遇到错误 continue, 循环结束后抛出异常

insertRecords = [{'i':i, 'date':'2017-10-10'} for i in range(10)]

insertBulk = db_coll.insert_many(insertRecords, ordered = True)

print(f"insert_ids={insertBulk.inserted_ids}")

# 结果:insert_ids=[ObjectId('59ad3ba851ad3e1104a4de6d'), ObjectId('59ad3ba851ad3e1104a4de6e'), ObjectId('59ad3ba851ad3e1104a4de6f'), ObjectId('59ad3ba851ad3e1104a4de70'), ObjectId('59ad3ba851ad3e1104a4de71'), ObjectId('59ad3ba851ad3e1104a4de72'), ObjectId('59ad3ba851ad3e1104a4de73'), ObjectId('59ad3ba851ad3e1104a4de74'), ObjectId('59ad3ba851ad3e1104a4de75'), ObjectId('59ad3ba851ad3e1104a4de76')]

1

2

3

4

5

6

7

5.3. 修改记录

# 根据筛选条件_id,更新这条记录。如果找不到符合条件的记录,就插入这条记录(upsert = True)

updateFilter = {'_id': item['_id']}

updateRes = db_coll.update_one(filter = updateFilter,

update = {'$set': dict(item)},

upsert = True)

print(f"updateRes = matched:{updateRes.matched_count}, modified = {updateRes.modified_count}")

1

2

3

4

5

6

7

# 根据筛选条件,更新部分字段:i是原有字段,isUpdated是新增字段

filterArgs = {'date':'2017-10-10'}

updateArgs = {'$set':{'isUpdated':True, 'i':100}}

updateRes = db_coll.update_many(filter = filterArgs, update = updateArgs)

print(f"updateRes: matched_count={updateRes.matched_count}, "

f"modified_count={updateRes.modified_count} modified_ids={updateRes.upserted_id}")

# 结果:updateRes: matched_count=8, modified_count=8 modified_ids=None

1

2

3

4

5

6

7

5.4. 删除记录

5.4.1. 删除一条记录

# 示例一:和查询使用的条件一样

queryArgs = {'endDate':'2017-08-28'}

delRecord = db_coll.delete_one(queryArgs)

print(f"delRecord={delRecord.deleted_count}")

# 结果:delRecord=1

1

2

3

4

5

5.4.2. 批量删除

# 示例二:和查询使用的条件一样

queryArgs = {'i':{'$gt':5, '$lt':8}}

# db_coll.delete_many({}) # 清空数据库

delRecord = db_coll.delete_many(queryArgs)

print(f"delRecord={delRecord.deleted_count}")

# 结果:delRecord=2

1

2

3

4

5

6

6. 将数据库文档写入csv文件。

6.1. 标准代码

读csv文件

import csv

with open("phoneCount.csv", "r") as csvfile:

reader = csv.reader(csvfile)

# 这里不需要readlines

for line in reader:

print(f"# line = {line}, typeOfLine = {type(line)}, lenOfLine = {len(line)}")

# 输出结果如下:

line = ['850', 'rest', '43', 'NN'], typeOfLine = , lenOfLine = 4

line = ['9865', 'min', '1', 'CD'], typeOfLine = , lenOfLine = 4

1

2

3

4

5

6

7

8

9

10

写csv文件

# 导出数据库所有记录的标准模版

import pymongo

import csv

# 初始化数据库

mongo_url = "127.0.0.1:27017"

DATABASE = "databaseName"

TABLE = "tableName"

client = pymongo.MongoClient(mongo_url)

db_des = client[DATABASE]

db_des_table = db_des[TABLE]

# 将数据写入到CSV文件中

# 如果直接从mongod booster导出, 一旦有部分出现字段缺失,那么会出现结果错位的问题

# newline='' 的作用是防止结果数据中出现空行,专属于python3

with open(f"{DATABASE}_{TABLE}.csv", "w", newline='') as csvfileWriter:

writer = csv.writer(csvfileWriter)

# 先写列名

# 写第一行,字段名

fieldList = [

"_id",

"itemType",

"field_1",

"field_2",

"field_3",

]

writer.writerow(fieldList)

allRecordRes = db_des_table.find()

# 写入多行数据

for record in allRecordRes:

print(f"record = {record}")

recordValueLst = []

for field in fieldList:

if field not in record:

recordValueLst.append("None")

else:

recordValueLst.append(record[field])

try:

writer.writerow(recordValueLst)

except Exception as e:

print(f"write csv exception. e = {e}")

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

6.2. 可能出现的问题以及解决方案

6.2.1. 写csv文件编码问题

参考文章:Python UnicodeEncodeError: ‘gbk’ codec can’t encode character 解决方法 :

http://www.jb51.net/article/64816.htm

重要点:目标文件的编码是导致标题所指问题的罪魁祸首。如果我们打开一个文件,在windows下面,新文件的默认编码是gbk,这样的话,python解释器会用gbk编码去解析我们的网络数据流txt,然而txt此时已经是decode过的unicode编码,这样的话就会导致解析不了,出现上述问题。 解决的办法就是,改变目标文件的编码。

解决方案:

###### 确实最推荐的做法是在open文件时,指定编码格式:

with open(f"{DATABASE}_{TABLE}.csv", "w", newline='', encoding='utf-8') as csvfileWriter:

# 就像我们在windows环境下,写csv文件时,默认编码是'gbk',而从网上获取的数据大部分是'utf-8',这就可能出现某些编码不兼容的问题。比如:write csv exception. e = 'gbk' codec can't encode character '\xae' in position 80: illegal multibyte sequence

1

2

3

6.2.2. 写csv文件出现空白行(存在一行间一行)

python2.x 版本

描述及解决方案,请参考:https://www.cnblogs.com/China-YangGISboy/p/7339118.html

# 为了解决这个问题,查了下资料,发现这是和打开方式有关,将打开的方法改为wb,就不存在这个问题了,也就是

在read/write csv 文件是要以binary的方式进行。

with open('result.csv','wb') as cf:

writer = csv.writer(cf)

writer.writerow(['shader','file'])

for key , value in result.items():

writer.writerow([key,value])

1

2

3

4

5

6

7

python2.x要用‘wb’模式写入的真正原因:

python2.x中写入CSV时,CSV文件的创建必须加上‘b’参数,即open('result.csv','wb'),不然会出现隔行的现象。原因是:python正常写入文件的时候,每行的结束默认添加'n’,即0x0D,而 writerow 命令的结束会再增加一个0x0D0A,因此对于windows系统来说,就是两行,而采用’ b'参数,用二进制进行文件写入,系统默认是不添加0x0D的

而且在python2.x中,str和bytes是存在很多隐性转换的,所以虽然CSV是文本文件,也是可以正常写入。

1

2

3

4

python3 版本

在python3中,str和bytes有了清晰的划分,也没有任何隐性的转换,csv 是文本格式的文件,不支持二进制的写入,所以不要用二进制模式打开文件,数据也不必转成bytes。

描述及解决方案,请参考:https://segmentfault.com/q/1010000006841656?_ea=1148776

# 解决方案就是 newline 配置成空即可

with open('result.csv', 'w', newline='') as csvfile:

1

2

总结一下:出现空白行的根本原因是Python版本问题,解决方案上python2.x中要求用‘wb’,python3.x中要求用 ‘w’ 和newline参数。

拓展:关于python3中bytes和string之间的互相转换:http://www.jb51.net/article/105064.htm

---------------------

作者:Kosmoo

来源:CSDN

原文:https://blog.csdn.net/zwq912318834/article/details/77689568

版权声明:本文为博主原创文章,转载请附上博文链接!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值