MongoDB
MongDB 的安装 链接
Windows:http://www.runoob.com/mongodb/mongodb-window-install.html
linux:http://www.runoob.com/mongodb/mongodb-linux-install.html
一、初识MongoDB
MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
简单说,MongoDB和我们使用的关系型数据库最大的区别就是约束性,可以说文件型数据库几乎不存在约束性,理论上没有主外键约束,没有存储的数据类型约束等等。关系型数据库中有一个 "表" 的概念,有 "字段" 的概念,有 "数据条目" 的概念,MongoDB中也同样有以上的概念,,但是名称发生了一些变化,严格意义上来说,两者的概念即为相似,但又有些出入,不过无所谓,我们就当是以上概念就好啦。
用如下示例进一步说明:
这是我们用关系型数据库做的一张很简单的user表:
id name age gender 1 刘涛 36 female 2 孙红雷 40 male 3 马伊利 35 female
在MongoDB的数据结构如下:
user = [ { "id": 1, "name": "刘涛", "age": 36, "gender": female }, { "id": 2, "name": "孙红雷", "age": 40, "gender": male }, { "id": 3, "name": "马伊利", "age": 35, "gender": female } ]
看到这里,你发现这不就是一个列表,里面放着三个字典吗?你说的对,如果你理解成了列表和字典,那么证明了你只会Python,在其他语言中它又是别的类型了,我们把这种类型叫做Json。
那么你应该恍然大悟了吧,MongoDB的每个表(Collection)中存储的每条数据(Documents)都是一个一个的Json,Json中的每一个字段(Key)我们称之为Field,就此我们引出了三个关键字:Collection也就是关系型数据库中"表"的概念,Documents就是"数据条目",Field就是"字段"。
接下来在你的电脑上安装MongoDB,本文以3.4版本为例,安装过程一路下一步即可,完成后找到安装目录下的bin目录,将其加入环境变量。
注意:安装完成后打开终端,输入mongod,会显示如下错误信息:
我们可以手动在上述提示目录,即c盘创建data\db目录,若不想放在c盘,也可以在其他磁盘,如d盘创建,如下:
此时就可以成功开启mongodb服务了,且要指定mongodb的数据存放目录,如下:
开启服务端后再打开一个终端开启mongo的客户端,如下:
接下来就可以进行mongodb的操作了,如下图:
注意:由上图我们发现,mongodb中使用了不存在的对象,就代表创建对象,接下来我们使用这以结论创建一张表(collection),如下图:
二、MongoDB的数据类型
ObjectID :Documents 自生成的 _id; String: 字符串,必须是utf-8; Boolean:布尔值,true 或者false (注意,这里首字母要小写); Integer:整数 (Int32、Int64,就知道有个Int就行了,一般我们用Int32); Double:浮点数 (没有float类型,所有小数都是Double); Arrays:数组或者列表,多个值存储到一个键; Object:相当于Python中的字典; Null:空数据类型; Timestamp:时间戳; Date:存储当前日期或时间unix时间格式 (我们一般不用这个Date类型,时间戳可以秒杀一切时间类型);
这里我们重点说一下ObjectID 类型, 它是MongoDB生成的类似关系DB表主键的唯一key, 具体由24个字节组成:
1-8字节是时间戳;
9-14字节的机器标识符, 表示MongoDB实例所在机器的不同;
15-18字节的进程id, 表示相同机器的不同MongoDB进程;
19-24字节是计数器;
"_id" : ObjectId("5c3ee043949505956bbf9b33") #"5c3ee043" 代指的是时间戳,这条数据的产生时间; #"949505" 代指某台机器的机器码,存储这条数据时的机器编号; #"956b" 代指进程ID,多进程存储数据的时候,非常有用的; #"bf9b33" 代指计数器,这里要注意的是,计数器的数字可能会出现重复,不是唯一的; # 以上四种标识符拼凑成世界上唯一的ObjectID # 只要是支持MongoDB的语言,都会有一个或多个方法,对ObjectID进行转换 # 注意:这个类型是不可以被JSON序列化的
三、MongoDB的增删改查
1, 插入数据 (insert, insertOne, insertMany)
insert(): 插入一条或者多条数据, 需要带有允许插入多条的参数, 这个方法目前官方已经不推荐了
insertOne({}) : 插入一条数据 , 官方推荐
insertMany([{}]):插入多条数据,无需参数控制,官方推荐
2, 查询数据 (find, findOne)
find(): 无条件查找, 将该表(Collection) 中所有的数据一次性返回
findOne(): 无条件查找一条数据, 默认当前Collection中第一条数据
find({条件}, {排除字段}), 示例如下 :
3, 修改数据 (update, updateOne, updateMany)
语法: update/updateOne/updateMany({条件}, {"关键字":{"修改内容"})
解释 : 根据条件修改内容, 其中如果条件为空, 那么将会修改Collection中所有的数据
示例:
update({"name":"tom"}, {$set:{"age":23}}); 表示将表中那么等于tom 的记录(documents) 的age字段(field) 改为23 , 与insert一样, 官方已经不推荐使用
updateOne({"age":23},{$set:{"age":24}}) ; 将表中age 等于 23 的记录(documents) 的age字段(field) 改为24 如果出现多条符合条件的记录, 只修改最靠前的数据, 3.2 版本之后有的, 官方推荐
updateMany({"age":25},{$set:{"age":22}}):将表中age等于25的记录(documents)的age字段(field)改为22,如出现多条符合条件的记录,修改所有符合条件的数据,3.2版本之后有的,官方推荐
4, 删除数据 (remove, deleteOne, deleteMany)
remove: 删除满足条件的数据或者删除全部数据, 官方已经不推荐使用了
deleteOne: 删除符合条件的一条数据, 若有多条符合条件, 默认删除符合条件的第一条, 3.2 版本之后又的, 官方推荐写法
deleteMany: 删除符合条件的所有数据, 若有多条符合提哦案件的则全部删除, 3.2 版本之后有的,官方推荐写法
5. 查询表中的数字比较关键字 ($lt, $gt, $lte, $gte, $eq)
$lt : MongoDB中的"<", 用 "$lt" , 比如: "age" : "age":{$lt:22} 就是得到"age" 小于22 的数据
$gt:MongoDB中的">",用"$gt",比如: "age":{$gt:22} 就是得到"age"大于22的数据
$lte : MongoDB中"<=" 用 "$lte" , 比如: "age":{$lte:22} 就是得到 "age" 小于等于22的数据
$gte : MongoDB中的">=" , 用 "$gte" , 比如:"age:{$gte:22}" 就是得到 "age" 大于等于22 的数据
$eq : 我们在之前的查询中遇到什么字段等于什么值时, 还是用冒号 " : " 来表示 , 比如 "name":"tom", 除此之外, MongoDB中的 "=", 还可以用关键字 " $eq " 表示, 比如 : "age": {$eq:22} 就是得到 "age" 等于22的数据, 但通常用冒号 ":" 表示即可, 不能用冒号的可用关键字 " $eq"
6, 查询条件并列关系, 或($or)关系, 子集($in)关系, 完全符合($all)关系
find({"name":"张三", "age"15})
find({$or:[{"name":"tom"},{"age":15}]})
find({"age":{$in:[10,20,30,40]}}) 或者 find({"score":{$in:[55,77,80,91]}})
find({"score":{$all:[58,88,79,95]}}) 排列不按顺序匹配
7 , MongoDB中的那些update修改器 ($inc, $set, $unset, $push, $pushAll, $pop)
在之前的update中, 我们用过$set 对数据进行修改, 其实在update中还存在很多的$关键字, 我们把update 中这些关键字叫做修改器, 修改器很多, 下面结合示例介绍几个:
1) $in : 将查询到的结果, 加上某一个值, 然后保存
2) $set: 暴力修改, 我们在MongoDB的基本操作中已经使用过该修改器
3) $unset : 用来暴力删除字段 (field)
4) $push: 用来对Array 数据类型进行 增加 新元素的, 相当于Python中list.append() 方法
5) $pull : 用来对Array数据类型进行 删除 元素的, 相当于Python中list.remove() 方法
6) $pushAll : 用来对Array数据类型进行 迭代追加, 相当于Python中list.extend() 方法
7)$pop : 指定删除Array中的第一个 或 最后一个元素
8 , "$" 符的奇妙用法
在MongoDB中有一个非常神奇的符号"$", "$" 在update中加上关键字就变成了修改器, 其实 "$" 字符独立出现也是有意义的, 它代表符合条件的元素下标
有如下collections:
现需要把tom的score_list列表中的59改为60,操作如下:
那么问题来了,若score_list中元素很多,且不知道要修改的元素索引,只知道修改前的值和修改后的值,此时改如何做呢?没错,就是使用"$",如下:
注意:$中只能存储一个值,且是符合条件的第一个值。
9, MongoDB 的Array , Object 的特殊操作
相比关系型数据库, Array和Object是MongoDB比较特殊的类型了, 特殊在哪里呢? 在他们的操作的上又有什么需要注意的呢?
我们先建立一条数据(documents),包含 Array 和 Object 类型:
{ "_id" : ObjectId("5c406c65456ef1f8f2b06401"), "name" : "tom", "score" : [ 98, 95, 90, 88 ], "girlfriend" : { "name" : "alex", "gender" : "female", "age" : 30 } }
1)示例一:将score列表中的90改为80
2)示例二:将tom的小于85的分数加上2分
3)示例三:$只能存储一个值
4)示例四:将girlfriend的age改为22
5)示例五:若tom的girlfriend的age小于25时,给其值加2
6)示例六:Array中嵌套Object的操作
我们再建立如下数据演示:
{ "_id" : ObjectId("5c407d5e456ef1f8f2b06402"), "name" : "tom", "chengji" : [ { "title" : "python", "desc" : "very good", "score" : 90 }, { "title" : "linux", "desc" : "bad", "score" : 60 }, { "title" : "java", "desc" : "good", "score" : 82 } ] }
db.userinfo.update({""chengji.score":{$lt:70}},{$inc:{"chengji.$.score":2}})
{"chegnji.score":{$lt:70}}, 虽然chegnji是Array, 表示从内部的Object中找到score小于70的结果
{$inc:{"chengji.$.score":2}}, chegnji中第$(小于70的第一个)个Object中score加2
10 , limit, skip, sort
1) limit 选取: 从documents 中取出多少个
2) Skip跳过: 跳过多少个Documents
3) sort 排序: 将结果按照关键字排序(1 为升序, -1为降序)
4) limit + skip + sort 混合使用
注意 : sort + skip +limit 是有执行优先级的, 他们的界别分别是, 优先Sort 其次Skip 最后limit
四, pymongo
类似pymysql,pymongo是python中操作mongodb数据库的模块。
1、安装
pip3 install pymongo
2、使用pymongo
1)增加
import pymongo mongoclient = pymongo.MongoClient(host="127.0.0.1", port=27017) MongoDB = mongoclient["db1"] # db1是mongodb中的一个数据库 res = MongoDB.userinfo.insert_one({"name":"heshun","age":18}) print(res) # <pymongo.results.InsertOneResult object at 0x0000021019461F48> print(type(res)) # <class 'pymongo.results.InsertOneResult'> print(res.inserted_id) # 5c444717e3a9e52b9c6c0491 print(type(res.inserted_id)) # <class 'bson.objectid.ObjectId'> res = MongoDB.userinfo.insert_many([ {"name":"张三","age":23}, {"name":"李四","age":34} ]) print(res) # <pymongo.results.InsertManyResult object at 0x0000024A75760148> print(type(res)) # <class 'pymongo.results.InsertManyResult'> print(res.inserted_ids) # [ObjectId('5c4447c3e3a9e523447f93e7'), ObjectId('5c4447c3e3a9e523447f93e8')]
总结:
-insert_one() 插入数据一条数据(documents), 返回值的insert_id 表示插入数据的"_id" 值, ObjectID类型;
-insert_many([])插入多条数据(documents), 返回值的inserted_ids表示插入数据的"_id" 值组成的列表, 列表中的元素也是ObjectID 类型;
2)查询
import pymongo mongoclient = pymongo.MongoClient(host="127.0.0.1", port=27017) MongoDB = mongoclient["db1"] # db1是mongodb中的一个数据库 res = MongoDB.userinfo.find_one() # 查询一条数据,返回字典 print(res) # {'_id': ObjectId('5c3ee043949505956bbf9b33'), 'name': 'tom', 'age': 12.0} res = MongoDB.userinfo.find() # 查询所有数据,返回cursor对象,可迭代 print(res) # <pymongo.cursor.Cursor object at 0x0000016CF07D7358> print(list(res)) # [{'_id': ObjectId('5c3ee043949505956bbf9b33'), 'name': 'tom', 'age': 12.0}, # {'_id': ObjectId('5c3eed9dcf0e440980eb4e45'), 'name': 'alex', 'age': 38}, # {'_id': ObjectId('5c3eee24cf0e440838f79d3a'), 'name': 'wusir', 'age': 32}, # {'_id': ObjectId('5c3eef71cf0e440ba4f5c40d'), 'name': '张三', 'age': 30}, # {'_id': ObjectId('5c3eef71cf0e440ba4f5c40e'), 'name': '李四', 'age': 18}]
注意 : 同mongodb一样, pymong也可以find({条件},{排除字段})或者find_one({条件},{排除字段})
3)修改
import pymongo mongoclient = pymongo.MongoClient(host="127.0.0.1", port=27017) MongoDB = mongoclient["db1"] # db1是mongodb中的一个数据库 res = MongoDB.userinfo.update_one({"name":"tom"},{"$set":{"age":15}}) print(res) # <pymongo.results.UpdateResult object at 0x000001A888325E08> print(dir(res)) # [..., '__delattr__',..., 'raw_result', 'upserted_id'] res = MongoDB.userinfo.update_many({"age":15},{"$set":{"age":22}}) print(res.raw_result) # 修改结果,包括影响行数,是否存在需要修改的数据等 # {'n': 2, 'nModified': 2, 'ok': 1.0, 'updatedExisting': True}
总结: 除上例中的$set之外, $push, $pull 等方法都可以使用
4)删除
import pymongo mongoclient = pymongo.MongoClient(host="127.0.0.1", port=27017) MongoDB = mongoclient["db1"] # db1是mongodb中的一个数据库 res = MongoDB.userinfo.delete_one({"name":"wusir"}) res = MongoDB.userinfo.delete_many({"age":22})
5)sort、limit、skip
import pymongo mongoclient = pymongo.MongoClient(host="127.0.0.1", port=27017) MongoDB = mongoclient["db1"] # db1是mongodb中的一个数据库 res = MongoDB.userinfo.find().skip(2).limit(2) # 跳过两条,显示两条 print(list(res)) # pymongo.ASCENDING表示升序,pymongo.DESCENDING表示降序 res = MongoDB.userinfo.find().sort("age", pymongo.ASCENDING) print(list(res)) res = MongoDB.userinfo.find().sort("age", pymongo.DESCENDING) print(list(res))
6) 字符串类型与ObjectID类型的相互转换
我们知道ObjectID不能被序列化, 而mongodb中的"_id" 是ObjectID 类型数据, 且经常需要将数据json序列化后进行传输,下面介绍字符串类型与ObjectID类型相互转换。
import pymongo from bson import ObjectId mongoclient = pymongo.MongoClient(host="127.0.0.1", port=27017) MongoDB = mongoclient["db1"] # db1是mongodb中的一个数据库 res = MongoDB.userinfo.find_one() s = res.get("_id") print(s) # 5c3eef71cf0e440ba4f5c40d print(type(s)) # <class 'bson.objectid.ObjectId'> print(str(s)) # 5c3eef71cf0e440ba4f5c40d print(type(str(s))) # <class 'str'> s = ObjectId("5c3eef71cf0e440ba4f5c40d") # 强转成ObjectID类型 res = MongoDB.userinfo.find_one({"_id":s}) print(res) # {'_id': ObjectId('5c3eef71cf0e440ba4f5c40d'), 'name': '张三', 'age': 30}