MongoDB其实就是个大JSON。在Python的世界里,dict也是最流行的类型,所以他们是天生的一对。推荐使用Docker来部署和管理MongoDB安装,一行命令即可完成。正式版:dockerrun-d--namemongodb\-eMONGO_INITDB_ROOT_USERNAME=admin\-eMONGO_INITDB_ROOT_PASSWORD=admin\-v~/data/mongo_dir:/data/db\-p27017:27017\mongo正式版的Docker什么都好,但尺寸有点大。还有一个小型的alpine版本,开发时使用非常方便,但是不能配置账号和密码。dockerrun-d--namemongo-lite\-p27018:27017\-v~/data/mongo_lite:/data/db\mvertes/alpine-mongo如果你想试试Mongo的命令行(MongoShell),直接进入Docker:$dockerexec-itmongo-litemongoMongoDBshellversionv4.0.6connectingto:mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb...>usemydbswitchedtodbmydb>db.User.insertOne({"name":"Toby",age:18}){"acknowledged":true,"insertedId":ObjectId("612c84c5d93795436ad27ebc")}>db.User.find(){"_id":ObjectId("612c84c5d93795436ad27ebc"),"name":"Toby","age":18}MongoShell官方文档:https://docs.mongodb.com/manual/reference/mongo-shell/PyMongo五分钟上手安装PyMongo可以通过pip完成。pipinstallpymongo的以下内容也可以参考官方文档:https://pymongo.readthedocs.io/en/stable/常用的连接数据库方式如下:frompymongoimportMongoClient#ConnectMongoclientwithpassword=MongoClient('mongodb://admin:admin@localhost:27017/')#无密码连接Mongoclient=MongoClient('mongodb://localhost:27018/')#列出所有存在的DBfordbinclient.list_databases():print(db)#使用某个Mongo中的DB,这个DB可能不存在,后面写数据的时候会创建。db=client.mydb插入数据。插入的每条数据都是一个字典。同一个字段允许不同的类型,也允许每次插入不同的数据字段。可以理解为动态类型的数据,你想放什么就放什么,唯一的限制就是它们会放在同一个Document中。#插入一条数据defadd_one_user():db.User.insert_one({'name':'Toby','age':18})#插入多条数据defadd_many_users():db.User.insert_many([{'name':'Tom','age':10},{'name':'Toby','age':'unknown','hobbies':['writebugs','raisedogs']}])用户这里约等于一个关系数据库表,但它的名字是Document。每次数据插入完成后,都会返回一个_id。这是Mongo中最重要的事情。它依靠这个_id来保证数据的一致性。后续的数据修改和删除主要是通过这个_id来完成的,所以一般对于具体某条数据的处理,需要先查询它的_id,然后再进行后续的操作。查询数据#查询多条数据defshow_users():#一张表中所有数据foreindb.User.find():print(e)#多条数据匹配条件foreindb.User.find({'name':'Toby'}):print(e)#查询单个数据defquery_user(name):returndb.User.find_one({'name':name})#忽略大小写defquery_user_ignore_case(name):returndb.User.find_one({'name':re.compile(name,re.IGNORECASE)})#使用运算符https://docs.mongodb.com/manual/reference/operator/query/defquery_teenager():returndb.User.find_one({'age':{'$lt':18}})Mongo的查询主要依赖DB本身提供的算子。在PyMongo中,需要注意的是这里不会抛出异常。如果找不到数据,则默认返回None。通过算子查询数据:https://docs.mongodb.com/manual/reference/operator/query/通过聚合查询数据:https://docs.mongodb.com/manual/aggregation/Modifydata#修改一个数据defupdate_user(user,attributes:dict):user.update(attributes)result=db.User.replace_one({'_id':user['_id']},user,upsert=True)return{'affected_count':result.modified_count}u=query_user_ignore_case('toby')result=update_user(u,{'code':'python'})#修改多条数据,注意陷阱,Replace和Update不一样defupdate_many():todo=[UpdateOne({'age':19},{'$set':{'name':'Toby'}}),ReplaceOne({'name':'Tom'},{'age':19}),#name会被吃掉]result=db.User.bulk_write(todo)defdelete_user(name):result=db.User.delete_one({'name':name})return{'affected_count':result.deleted_count}print(result.matched_count)替换为一个替换,所以需要带上原来的字段,这里有点坑。更新不接受单独的字典,它需要一种方法来$set/$unset来识别修改的字段。[{$set:{status:"Modified",comments:["$misc1","$misc2"]}},{$unset:["misc1","misc2"]}]删除数据defdelete_user(name):result=db.User.delete_one({'name':name})return{'affected_count':result.deleted_count}删除多条数据:>>>db.test.count_documents({'x':1})3>>>result=db.test.delete_many({'x':1})>>>result.deleted_count3>>>db.test.count_documents({'x':1})0FAQ有没有办法让Mongo做不会自动将_id添加到我的数据中?几乎没有,这是由MongoDB的特性决定的。如果你的数据没有ID,当你进行高并发插入时,很可能会遇到BulkWriteError错误。>>>doc={}>>>collection.insert_many(docfor_inrange(10))Traceback(mostrecentcallast):...pymongo.errors.BulkWriteError:batchoperrorsoccurred>>>doc{'_id':ObjectId('560f171cfba52279f0b0da0c')}>>>docs=[{}]>>>collection.insert_many(docs*10)Traceback(mostrecentcalllast):...pymongo.errors.BulkWriteError:batchoperrorsoccurred>>>docs[{'_id':ObjectId('560f1933fba52279f0b0da0e')}]如果你不想要自动生成的ID,你可以在插入数据之前自己指定这个字段。为什么指定_id后查询不到我的数据?比如我要查询数据库中的一个帖子:>>>post_id_as_str=str(post_id)>>>posts.find_one({"_id":post_id_as_str})#Noresult因为pyMongo中的ID不是字符串类型,你需要做一些数据转换。frombson.objectidimportObjectId#Thewebframeworkgetspost_idfromtheURL和passesitasastringdefget(post_id):#ConvertfromstringtoObjectId:document=client.db.collection.find_one({'_id':ObjectId(post_id)})使用标准库中的json模块序列化和反序列化Mongo数据会是什么问题?有些数据类型在反序列化后得不到预期的结果,比如ObjectId、DBRef。为了解决这个问题,PyMongo封装了一个辅助类json_util,可以很好的解决这些问题。来自bson.json.json_utilimportloadsfrombson.json_utilimportdumps的总结Mongo是非关系型数据库,将Mongo作为DB使用的思路需要比较大的改变:关系型数据库一般读写容易,修改困难。很容易理解,非关系型数据库一般都是容易读写的。设计难度(相对而言)》关系型数据库支持ACID(Atomicity,Consistency,Isolation,Duration)即原子性、一致性、隔离性和持久性。相对而言,NoSQL采用更宽松的模型BASE(BasicallyAvailable,Softstate,EventualConsistency)意味着基本可用,软状态和最终一致性,NoSQL在精心设计下会有更高的查询性能,数据结构也非常灵活,特别适合快速发展和不确定属性的产品功能,但是Mongo不支持事务,如何保证数据一致性是一个很大的挑战,选择时可以从以下几个角度考虑:需要ACID还是BASE需要结构化数据还是非结构化数据需要灵活扩展数据开发人员有很多经验的情况只考虑最后一点。
