MongoDB開始火了,這是時代發展的需要。為此,本教程也要涉及到如何用python來操作mongodb。考慮到讀者對這種數據庫可能比mysql之類的更陌生,所以,要用多一點的篇幅稍作介紹,當然,更完備的內容還是要去閱讀專業的mongodb書籍。
mongodb是屬于NoSql的。
NoSql,全稱是 Not Only Sql,指的是非關系型的數據庫。它是為了大規模web應用而生的,其特征諸如模式自由、支持簡易復制、簡單的API、大容量數據等等。
MongoDB是其一,選擇它,主要是因為我喜歡,否則我不會列入我的教程。數說它的特點,可能是:
* 面向文檔存儲
* 對任何屬性可索引
* 復制和高可用性
* 自動分片
* 豐富的查詢
* 快速就地更新
也許還能列出更多,基于它的特點,擅長領域就在于:
* 大數據(太時髦了!以下可以都不看,就要用它了。)
* 內容管理和交付
* 移動和社交基礎設施
* 用戶數據管理
* 數據平臺
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/232.md#安裝mongodb)安裝mongodb
先演示在ubuntu系統中的安裝過程:
~~~
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list
sudo apt-get update
sudo apt-get install mongodb-10gen
~~~
如此就安裝完畢。上述安裝流程來自:[Install MongoDB](http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/)
如果你用的是其它操作系統,可以到官方網站下載安裝程序:[http://www.mongodb.org/downloads](http://www.mongodb.org/downloads),能滿足各種操作系統。
[](https://github.com/qiwsir/StarterLearningPython/blob/master/2images/23201.jpg)
> 難免在安裝過程中遇到問題,推薦幾個資料,供參考:
>
> [window平臺安裝 MongoDB](http://www.w3cschool.cc/mongodb/mongodb-window-install.html)
>
> [NoSQL之【MongoDB】學習(一):安裝說明](http://www.cnblogs.com/zhoujinyi/archive/2013/06/02/3113868.html)
>
> [MongoDB 生產環境的安裝與配置(Ubuntu)](https://ruby-china.org/topics/454)
>
> [在Ubuntu中安裝MongoDB](http://blog.fens.me/linux-mongodb-install/)
>
> [在Ubuntu下進行MongoDB安裝步驟](https://github.com/qiwsir/StarterLearningPython/blob/master/www.cnblogs.com/alexqdh/archive/2011/11/25/2263626.html)
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/232.md#啟動mongodb)啟動mongodb
安裝完畢,就可以啟動數據庫。因為本教程不是專門講數據庫,所以,這里不設計數據庫的詳細講解,請讀者參考有關資料。下面只是建立一個簡單的庫,并且說明mongodb的基本要點,目的在于為后面用python來操作它做個鋪墊。
執行`mongo`啟動shell,顯示的也是`>`,有點類似mysql的狀態。在shell中,可以實現與數據庫的交互操作。
在shell中,有一個全局變量db,使用哪個數據庫,那個數據庫就會被復制給這個全局變量db,如果那個數據庫不存在,就會新建。
~~~
> use mydb
switched to db mydb
> db
mydb
~~~
除非向這個數據庫中增加實質性的內容,否則它是看不到的。
~~~
> show dbs;
local 0.03125GB
~~~
向這個數據庫增加點東西。mongodb的基本單元是文檔,所謂文檔,就類似與python中的字典,以鍵值對的方式保存數據。
~~~
> book = {"title":"from beginner to master", "author":"qiwsir", "lang":"python"}
{
"title" : "from beginner to master",
"author" : "qiwsir",
"lang" : "python"
}
> db.books.insert(book)
> db.books.find()
{ "_id" : ObjectId("554f0e3cf579bc0767db9edf"), "title" : "from beginner to master", "author" : "qiwsir", "lang" : "python" }
~~~
db指向了數據庫mydb,books是這個數據庫里面的一個集合(類似mysql里面的表),向集合books里面插入了一個文檔(文檔對應mysql里面的記錄)。“數據庫、集合、文檔”構成了mongodb數據庫。
從上面操作,還發現一個有意思的地方,并沒有類似create之類的命令,用到數據庫,就通過`use xxx`,如果不存在就建立;用到集合,就通過`db.xxx`來使用,如果沒有就建立。可以總結為“隨用隨取隨建立”。是不是簡單的有點出人意料。
~~~
> show dbs
local 0.03125GB
mydb 0.0625GB
~~~
當有了充實內容之后,也看到剛才用到的數據庫mydb了。
在mongodb的shell中,可以對數據進行“增刪改查”等操作。但是,我們的目的是用python來操作,所以,還是把力氣放在后面用。
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/232.md#安裝pymongo)安裝pymongo
要用python來驅動mongodb,必須要安裝驅動模塊,即pymongo,這跟操作mysql類似。安裝方法,我最推薦如下:
~~~
$ sudo pip install pymongo
~~~
如果順利,就會看到最后的提示:
~~~
Successfully installed pymongo
Cleaning up...
~~~
如果不選擇版本,安裝的應該是最新版本的,我在本教程測試的時候,安裝的是:
~~~
>>> import pymongo
>>> pymongo.version
'3.0.1'
~~~
這個版本在后面給我挖了一個坑。如果讀者要指定版本,比如安裝2.8版本的,可以:
~~~
$ sudo pip install pymongo==2.8
~~~
如果用這個版本,我后面遇到的坑能夠避免。
安裝好之后,進入到python的交互模式里面:
~~~
>>> import pymongo
~~~
說明模塊沒有問題。
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/232.md#連接mongodb)連接mongodb
既然python驅動mongdb的模塊pymongo業已安裝完畢,接下來就是連接,也就是建立連接對象。
~~~
>>> pymongo.Connection("localhost",27017)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'Connection'
~~~
報錯!我在去年做的項目中,就是這樣做的,并且網上查看很多教程都是這么連接。
所以,讀者如果用的是舊版本的pymongo,比如2.8,仍然可以使用上面的連接方法,如果是像我一樣,是用的新的(我安裝時沒有選版本),就得注意這個問題了。
經驗主義害死人。必須看看下面有哪些方法可以用:
~~~
>>> dir(pymongo)
['ALL', 'ASCENDING', 'CursorType', 'DESCENDING', 'DeleteMany', 'DeleteOne', 'GEO2D', 'GEOHAYSTACK', 'GEOSPHERE', 'HASHED', 'IndexModel', 'InsertOne', 'MAX_SUPPORTED_WIRE_VERSION', 'MIN_SUPPORTED_WIRE_VERSION', 'MongoClient', 'MongoReplicaSetClient', 'OFF', 'ReadPreference', 'ReplaceOne', 'ReturnDocument', 'SLOW_ONLY', 'TEXT', 'UpdateMany', 'UpdateOne', 'WriteConcern', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '_cmessage', 'auth', 'bulk', 'client_options', 'collection', 'command_cursor', 'common', 'cursor', 'cursor_manager', 'database', 'errors', 'get_version_string', 'has_c', 'helpers', 'ismaster', 'message', 'mongo_client', 'mongo_replica_set_client', 'monitor', 'monotonic', 'network', 'operations', 'periodic_executor', 'pool', 'read_preferences', 'response', 'results', 'server', 'server_description', 'server_selectors', 'server_type', 'settings', 'son_manipulator', 'ssl_context', 'ssl_support', 'thread_util', 'topology', 'topology_description', 'uri_parser', 'version', 'version_tuple', 'write_concern']
~~~
瞪大我的那雙渾濁迷茫布滿血絲渴望驚喜的眼睛,透過近視鏡的玻璃片,怎么也找不到Connection()這個方法。原來,剛剛安裝的pymongo變了,“他變了”。
不過,我發現了它:MongoClient()
~~~
>>> client = pymongo.MongoClient("localhost", 27017)
~~~
很好。python已經和mongodb建立了連接。
剛才已經建立了一個數據庫mydb,并且在這個庫里面有一個集合books,于是:
~~~
>>> db = client.mydb
~~~
或者
~~~
>>> db = client['mydb']
~~~
獲得數據庫mydb,并賦值給變量db(這個變量不是mongodb的shell中的那個db,此處的db就是python中一個尋常的變量)。
~~~
>>> db.collection_names()
[u'system.indexes', u'books']
~~~
查看集合,發現了我們已經建立好的那個books,于是在獲取這個集合,并賦值給一個變量books:
~~~
>>> books = db["books"]
~~~
或者
~~~
>>> books = db.books
~~~
接下來,就可以操作這個集合中的具體內容了。
### [](https://github.com/qiwsir/StarterLearningPython/blob/master/232.md#編輯)編輯
剛剛的books所引用的是一個mongodb的集合對象,它就跟前面學習過的其它對象一樣,有一些方法供我們來驅使。
~~~
>>> type(books)
<class 'pymongo.collection.Collection'>
>>> dir(books)
['_BaseObject__codec_options', '_BaseObject__read_preference', '_BaseObject__write_concern', '_Collection__create', '_Collection__create_index', '_Collection__database', '_Collection__find_and_modify', '_Collection__full_name', '_Collection__name', '__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattr__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__iter__', '__module__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_command', '_count', '_delete', '_insert', '_socket_for_primary_reads', '_socket_for_reads', '_socket_for_writes', '_update', 'aggregate', 'bulk_write', 'codec_options', 'count', 'create_index', 'create_indexes', 'database', 'delete_many', 'delete_one', 'distinct', 'drop', 'drop_index', 'drop_indexes', 'ensure_index', 'find', 'find_and_modify', 'find_one', 'find_one_and_delete', 'find_one_and_replace', 'find_one_and_update', 'full_name', 'group', 'index_information', 'initialize_ordered_bulk_op', 'initialize_unordered_bulk_op', 'inline_map_reduce', 'insert', 'insert_many', 'insert_one', 'list_indexes', 'map_reduce', 'name', 'next', 'options', 'parallel_scan', 'read_preference', 'reindex', 'remove', 'rename', 'replace_one', 'save', 'update', 'update_many', 'update_one', 'with_options', 'write_concern']
~~~
這么多方法不會一一介紹,只是按照“增刪改查”的常用功能,介紹幾種。讀者可以使用help()去查看每一種方法的使用說明。
~~~
>>> books.find_one()
{u'lang': u'python', u'_id': ObjectId('554f0e3cf579bc0767db9edf'), u'author': u'qiwsir', u'title': u'from beginner to master'}
~~~
提醒讀者注意的是,如果你熟悉了mongodb的shell中的命令,跟pymongo中的方法稍有差別,比如剛才這個,在mongodb的shell中是這樣子的:
~~~
> db.books.findOne()
{
"_id" : ObjectId("554f0e3cf579bc0767db9edf"),
"title" : "from beginner to master",
"author" : "qiwsir",
"lang" : "python"
}
~~~
請注意區分。
目前在集合books中,有一個文檔,還想再增加,于是插入一條:
**新增和查詢**
~~~
>>> b2 = {"title":"physics", "author":"Newton", "lang":"english"}
>>> books.insert(b2)
ObjectId('554f28f465db941152e6df8b')
~~~
成功地向集合中增加了一個文檔。得看看結果(我們就是充滿好奇心的小孩子,我記得女兒小時候,每個給她照相,拍了一張,她總要看一看。現在我們似乎也是這樣,如果不看看,總覺得不放心),看看就是一種查詢。
~~~
>>> books.find().count()
2
~~~
這是查看當前集合有多少個文檔的方式,返回值為2,則說明有兩條文檔了。還是要看看內容。
~~~
>>> books.find_one()
{u'lang': u'python', u'_id': ObjectId('554f0e3cf579bc0767db9edf'), u'author': u'qiwsir', u'title': u'from beginner to master'}
~~~
這個命令就不行了,因為它只返回第一條。必須要:
~~~
>>> for i in books.find():
... print i
...
{u'lang': u'python', u'_id': ObjectId('554f0e3cf579bc0767db9edf'), u'author': u'qiwsir', u'title': u'from beginner to master'}
{u'lang': u'english', u'title': u'physics', u'_id': ObjectId('554f28f465db941152e6df8b'), u'author': u'Newton'}
~~~
在books引用的對象中有find()方法,它返回的是一個可迭代對象,包含著集合中所有的文檔。
由于文檔是鍵值對,也不一定每條文檔都要結構一樣,比如,也可以插入這樣的文檔進入集合。
~~~
>>> books.insert({"name":"Hertz"})
ObjectId('554f2b4565db941152e6df8c')
>>> for i in books.find():
... print i
...
{u'lang': u'python', u'_id': ObjectId('554f0e3cf579bc0767db9edf'), u'author': u'qiwsir', u'title': u'from beginner to master'}
{u'lang': u'english', u'title': u'physics', u'_id': ObjectId('554f28f465db941152e6df8b'), u'author': u'Newton'}
{u'_id': ObjectId('554f2b4565db941152e6df8c'), u'name': u'Hertz'}
~~~
如果有多個文檔,想一下子插入到集合中(在mysql中,可以實現多條數據用一條命令插入到表里面,還記得嗎?忘了看[上一節](https://github.com/qiwsir/StarterLearningPython/blob/master/231.md)),可以這么做:
~~~
>>> n1 = {"title":"java", "name":"Bush"}
>>> n2 = {"title":"fortran", "name":"John Warner Backus"}
>>> n3 = {"title":"lisp", "name":"John McCarthy"}
>>> n = [n1, n2, n3]
>>> n
[{'name': 'Bush', 'title': 'java'}, {'name': 'John Warner Backus', 'title': 'fortran'}, {'name': 'John McCarthy', 'title': 'lisp'}]
>>> books.insert(n)
[ObjectId('554f30be65db941152e6df8d'), ObjectId('554f30be65db941152e6df8e'), ObjectId('554f30be65db941152e6df8f')]
~~~
這樣就完成了所謂的批量插入,查看一下文檔條數:
~~~
>>> books.find().count()
6
~~~
但是,要提醒讀者,批量插入的文檔大小是有限制的,網上有人說不要超過20萬條,有人說不要超過16MB,我沒有測試過。在一般情況下,或許達不到上線,如果遇到極端情況,就請讀者在使用時多注意了。
如果要查詢,除了通過循環之外,能不能按照某個條件查呢?比如查找`'name'='Bush'`的文檔:
~~~
>>> books.find_one({"name":"Bush"})
{u'_id': ObjectId('554f30be65db941152e6df8d'), u'name': u'Bush', u'title': u'java'}
~~~
對于查詢結果,還可以進行排序:
~~~
>>> for i in books.find().sort("title", pymongo.ASCENDING):
... print i
...
{u'_id': ObjectId('554f2b4565db941152e6df8c'), u'name': u'Hertz'}
{u'_id': ObjectId('554f30be65db941152e6df8e'), u'name': u'John Warner Backus', u'title': u'fortran'}
{u'lang': u'python', u'_id': ObjectId('554f0e3cf579bc0767db9edf'), u'author': u'qiwsir', u'title': u'from beginner to master'}
{u'_id': ObjectId('554f30be65db941152e6df8d'), u'name': u'Bush', u'title': u'java'}
{u'_id': ObjectId('554f30be65db941152e6df8f'), u'name': u'John McCarthy', u'title': u'lisp'}
{u'lang': u'english', u'title': u'physics', u'_id': ObjectId('554f28f465db941152e6df8b'), u'author': u'Newton'}
~~~
這是按照"title"的值的升序排列的,注意sort()中的第二個參數,意思是升序排列。如果按照降序,就需要將參數修改為`pymongo.DESCEDING`,也可以指定多個排序鍵。
~~~
>>> for i in books.find().sort([("name",pymongo.ASCENDING),("name",pymongo.DESCENDING)]):
... print i
...
{u'_id': ObjectId('554f30be65db941152e6df8e'), u'name': u'John Warner Backus', u'title': u'fortran'}
{u'_id': ObjectId('554f30be65db941152e6df8f'), u'name': u'John McCarthy', u'title': u'lisp'}
{u'_id': ObjectId('554f2b4565db941152e6df8c'), u'name': u'Hertz'}
{u'_id': ObjectId('554f30be65db941152e6df8d'), u'name': u'Bush', u'title': u'java'}
{u'lang': u'python', u'_id': ObjectId('554f0e3cf579bc0767db9edf'), u'author': u'qiwsir', u'title': u'from beginner to master'}
{u'lang': u'english', u'title': u'physics', u'_id': ObjectId('554f28f465db941152e6df8b'), u'author': u'Newton'}
~~~
讀者如果看到這里,請務必注意一個事情,那就是mongodb中的每個文檔,本質上都是“鍵值對”的類字典結構。這種結構,一經python讀出來,就可以用字典中的各種方法來操作。與此類似的還有一個名為json的東西,可以閱讀本教程第貳季進階的第陸章模塊中的[《標準庫(8)](https://github.com/qiwsir/StarterLearningPython/blob/master/227.md)。但是,如果用python讀過來之后,無法直接用json模塊中的json.dumps()方法操作文檔。其中一種解決方法就是將文檔中的`'_id'`鍵值對刪除(例如:`del doc['_id']`),然后使用json.dumps()即可。讀者也可是使用json_util模塊,因為它是“Tools for using Python’s json module with BSON documents”,請閱讀[http://api.mongodb.org/python/current/api/bson/json_util.html](http://api.mongodb.org/python/current/api/bson/json_util.html)中的模塊使用說明。
**更新**
對于已有數據,進行更新,是數據庫中常用的操作。比如,要更新name為Hertz那個文檔:
~~~
>>> books.update({"name":"Hertz"}, {"$set": {"title":"new physics", "author":"Hertz"}})
{u'updatedExisting': True, u'connectionId': 4, u'ok': 1.0, u'err': None, u'n': 1}
>>> books.find_one({"author":"Hertz"})
{u'title': u'new physics', u'_id': ObjectId('554f2b4565db941152e6df8c'), u'name': u'Hertz', u'author': u'Hertz'}
~~~
在更新的時候,用了一個`$set`修改器,它可以用來指定鍵值,如果鍵不存在,就會創建。
關于修改器,不僅僅是這一個,還有別的呢。
| 修改器 | 描述 |
| --- | --- |
| $set | 用來指定一個鍵的值。如果不存在則創建它 |
| $unset | 完全刪除某個鍵 |
| $inc | 增加已有鍵的值,不存在則創建(只能用于增加整數、長整數、雙精度浮點數) |
| $push | 數組修改器只能操作值為數組,存在key在值末尾增加一個元素,不存在則創建一個數組 |
**刪除**
刪除可以用remove()方法:
~~~
>>> books.remove({"name":"Bush"})
{u'connectionId': 4, u'ok': 1.0, u'err': None, u'n': 1}
>>> books.find_one({"name":"Bush"})
>>>
~~~
這是將那個文檔全部刪除。當然,也可以根據mongodb的語法規則,寫個條件,按照條件刪除。
**索引**
索引的目的是為了讓查詢速度更快,當然,在具體的項目開發中,要視情況而定是否建立索引。因為建立索引也是有代價的。
~~~
>>> books.create_index([("title", pymongo.DESCENDING),])
u'title_-1'
~~~
我這里僅僅是對pymongo模塊做了一個非常簡單的介紹,在實際使用過程中,上面知識是很有限的,所以需要讀者根據具體應用場景再結合mongodb的有關知識去嘗試新的語句。
- 第零章 預備
- 關于Python的故事
- 從小工到專家
- Python安裝
- 集成開發環境
- 第壹章 基本數據類型
- 數和四則運算
- 除法
- 常用數學函數和運算優先級
- 寫一個簡單的程序
- 字符串(1)
- 字符串(2)
- 字符串(3)
- 字符串(4)
- 字符編碼
- 列表(1)
- 列表(2)
- 列表(3)
- 回顧list和str
- 元組
- 字典(1)
- 字典(2)
- 集合(1)
- 集合(2)
- 第貳章 語句和文件
- 運算符
- 語句(1)
- 語句(2)
- 語句(3)
- 語句(4)
- 語句(5)
- 文件(1)
- 文件(2)
- 迭代
- 練習
- 自省
- 第叁章 函數
- 函數(1)
- 函數(2)
- 函數(3)
- 函數(4)
- 函數練習
- 第肆章 類
- 類(1)
- 類(2)
- 類(3)
- 類(4)
- 類(5)
- 多態和封裝
- 特殊方法(1)
- 特殊方法(2)
- 迭代器
- 生成器
- 上下文管理器
- 第伍章 錯誤和異常
- 錯誤和異常(1)
- 錯誤和異常(2)
- 錯誤和異常(3)
- 第陸章 模塊
- 編寫模塊
- 標準庫(1)
- 標準庫(2)
- 標準庫(3)
- 標準庫(4)
- 標準庫(5)
- 標準庫(6)
- 標準庫(7)
- 標準庫(8)
- 第三方庫
- 第柒章 保存數據
- 將數據存入文件
- mysql數據庫(1)
- MySQL數據庫(2)
- mongodb數據庫(1)
- SQLite數據庫
- 電子表格
- 第捌章 用Tornado做網站
- 為做網站而準備
- 分析Hello
- 用tornado做網站(1)
- 用tornado做網站(2)
- 用tornado做網站(3)
- 用tornado做網站(4)
- 用tornado做網站(5)
- 用tornado做網站(6)
- 用tornado做網站(7)
- 第玖章 科學計算
- 為計算做準備
- Pandas使用(1)
- Pandas使用(2)
- 處理股票數據
- 附:網絡文摘
- 如何成為Python高手
- ASCII、Unicode、GBK和UTF-8字符編碼的區別聯系