1. 程式人生 > >孤荷凌寒自學python第五十九天嘗試使用python來讀訪問遠端MongoDb資料服務

孤荷凌寒自學python第五十九天嘗試使用python來讀訪問遠端MongoDb資料服務

孤荷凌寒自學python第五十九天嘗試使用python來讀訪問遠端MongoDb資料服務

 

(完整學習過程螢幕記錄視訊地址在文末)

 

今天是學習mongoDB資料庫的第五天。今天的感覺是,mongoDB資料庫我似乎根本就很難掌控呵!

 

一、首先系統學習了讀寫mongoDB資料庫的方法

以下筆記來自官方文件整理:

(官方文件:https://api.mongodb.com/python/current/index.html

(一)指定資料庫

MongoDB中還分為一個個資料庫,我們接下來的一步就是指定要操作哪個資料庫,在這裡我以test資料庫為例進行說明,所以下一步我們需要在程式中指定要使用的資料庫。

db = client.test

呼叫client的test屬性即可返回test資料庫,當然也可以這樣來指定:

db = client['test']

兩種方式是等價的。

(二)指定集合

MongoDB的每個資料庫又包含了許多集合Collection,也就類似與關係型資料庫中的表,下一步我們需要指定要操作的集合,在這裡我們指定一個集合名稱為students,學生集合。還是和指定資料庫類似,指定集合也有兩種方式。

collection = db.students

#collection = db['students']

 

(三)插入資料

接下來我們便可以進行資料插入了,對於students這個Collection,我們新建一條學生資料,以字典的形式表示:

student = {

 'id': '20170101',

 'name': 'Jordan',

 'age': 20,

 'gender': 'male'

}

 

在這裡我們指定了學生的學號、姓名、年齡和性別,然後接下來直接呼叫collection的insert()方法即可插入資料。

 

result = collection.insert(student)

print(result)

 

在MongoDB中,每條資料其實都有一個_id屬性來唯一標識,如果沒有顯式指明_id,MongoDB會自動產生一個ObjectId型別的_id屬性。insert()方法會在執行後返回的_id值。

 

執行結果:

 

5932a68615c2606814c91f3d

 

當然我們也可以同時插入多條資料,只需要以列表形式傳遞即可,示例如下:

 

student1 = {

 'id': '20170101',

 'name': 'Jordan',

 'age': 20,

 'gender': 'male'

}

 

student2 = {

 'id': '20170202',

 'name': 'Mike',

 'age': 21,

 'gender': 'male'

}

 

result = collection.insert([student1, student2])

print(result)

 

返回的結果是對應的_id的集合,執行結果:

 

[ObjectId('5932a80115c2606a59e8a048'), ObjectId('5932a80115c2606a59e8a049')]

 

實際上在PyMongo 3.X版本中,insert()方法官方已經不推薦使用了,當然繼續使用也沒有什麼問題,官方推薦使用insert_one()和insert_many()方法將插入單條和多條記錄分開。

student = {

 'id': '20170101',

 'name': 'Jordan',

 'age': 20,

 'gender': 'male'

}

 

result = collection.insert_one(student)

print(result)

print(result.inserted_id)

 

執行結果:

<pymongo.results.InsertOneResult object at 0x10d68b558>

5932ab0f15c2606f0c1cf6c5

 

返回結果和insert()方法不同,這次返回的是InsertOneResult物件,我們可以呼叫其inserted_id屬性獲取_id。

 

對於insert_many()方法,我們可以將資料以列表形式傳遞即可,示例如下:

 

student1 = {

 'id': '20170101',

 'name': 'Jordan',

 'age': 20,

 'gender': 'male'

}

 

student2 = {

 'id': '20170202',

 'name': 'Mike',

 'age': 21,

 'gender': 'male'

}

 

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

print(result)

print(result.inserted_ids)

 

insert_many()方法返回的型別是InsertManyResult,呼叫inserted_ids屬性可以獲取插入資料的_id列表,執行結果:

 

<pymongo.results.InsertManyResult object at 0x101dea558>

[ObjectId('5932abf415c2607083d3b2ac'), ObjectId('5932abf415c2607083d3b2ad')]

 

(四)查詢記錄

 

插入資料後我們可以利用find_one()或find()方法進行查詢,find_one()查詢得到是單個結果,find()則返回多個結果。

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

print(type(result))

print(result)

 

在這裡我們查詢name為Mike的資料,它的返回結果是字典型別,執行結果:

<class 'dict'>

{'_id': ObjectId('5932a80115c2606a59e8a049'), 'id': '20170202', 'name': 'Mike', 'age': 21, 'gender': 'male'}

 

可以發現它多了一個_id屬性,這就是MongoDB在插入的過程中自動新增的。

 

我們也可以直接根據ObjectId來查詢,這裡需要使用bson庫裡面的ObjectId。

 

from bson.objectid import ObjectId

 

result = collection.find_one({'_id': ObjectId('593278c115c2602667ec6bae')})

print(result)

 

其查詢結果依然是字典型別,執行結果:

{'_id': ObjectId('593278c115c2602667ec6bae'), 'id': '20170101', 'name': 'Jordan', 'age': 20, 'gender': 'male'}

 

當然如果查詢結果不存在則會返回None。

 

對於多條資料的查詢,我們可以使用find()方法,例如在這裡查詢年齡為20的資料,示例如下:

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

print(results)

for result in results:

 print(result)

 

執行結果:

 

<pymongo.cursor.Cursor object at 0x1032d5128>

{'_id': ObjectId('593278c115c2602667ec6bae'), 'id': '20170101', 'name': 'Jordan', 'age': 20, 'gender': 'male'}

{'_id': ObjectId('593278c815c2602678bb2b8d'), 'id': '20170102', 'name': 'Kevin', 'age': 20, 'gender': 'male'}

{'_id': ObjectId('593278d815c260269d7645a8'), 'id': '20170103', 'name': 'Harden', 'age': 20, 'gender': 'male'}

 

返回結果是Cursor型別,相當於一個生成器,我們需要遍歷取到所有的結果,每一個結果都是字典型別。

 

如果要查詢年齡大於20的資料,則寫法如下:

 

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

 

在這裡查詢的條件鍵值已經不是單純的數字了,而是一個字典,其鍵名為比較符號$gt,意思是大於,鍵值為20,這樣便可以查詢出所有年齡大於20的資料。

比較符號的含義歸納:

$lt 小於 示例:{'age': {'$lt': 20}}

$gt 大於 示例:{'age': {'$gt': 20}}

$lte 小於等於 示例:{'age': {'$lte': 20}}

$gte 大於等於 示例: {'age': {'$gte': 20}}

$ne 不等於 示例: {'age': {'$ne': 20}}

$in 在範圍內 示例: {'age': {'$in': [20, 23]}}

$nin 不在範圍內 示例:{'age': {'$nin': [20, 23]}}

 

二、根據上面的系統學習,感覺很輕鬆搞定,於是開始測試

```

from pymongo import MongoClient

 

import _mty

import _mf

import _mre

import _cl

 

def msgbox(info,titletext='孤荷凌寒的對話方塊QQ578652607',style=0,isShowErrMsg=False):

    return _mty.msgboxGhlh(info,titletext,style,isShowErrMsg)

 

def secondConnect():

    #--指明資料庫伺服器的地址與埠號:

    stru=_mf.readAllTextFromTxtFileGhlh('u.txt')

    strp=_mf.readAllTextFromTxtFileGhlh('p.txt')

    strhost='mongodb://' + stru + ':' + strp + '@cluster0-zr7xj.mongodb.net/?authMechanism=SCRAM-SHA-256'

    #--建立連線

    client=MongoClient(strhost,tz_aware=True,connect=True)

    #client=MongoClient("cluster0-zr7xj.mongodb.net",username=stru,password=strp,authMechanism='SCRAM-SHA-256',connect=False)

    #-- 獲取資料庫的命名標識

 

    #print(client.admin.command('ismaster'))

 

    db2=client.ghlhfirst

    #--獲取其中的一個集合物件

    jh=db2.ghlhone

    #msgbox(str(jh.info))

 

    #--查詢這個集合其中的記錄

   

    print(jh.find_one({"姓名":"張三"}))

 

secondConnect()

```

每次前面都執行正常,總是到了:

print(jh.find_one({"姓名":"張三"}))

這句時要等大概一分鐘,然後報錯:

pymongo.errors.ServerSelectionTimeoutError: cluster0-zr7xj.mongodb.net:27017: [Errno 11001] getaddrinfo failed

 

於是我就開始不停的搜尋,前後花了至少3個多小時,反覆測試,到底為什麼連線上了卻不能讀出(查詢)出任何內容來呢,真的弄得自己筋疲力盡。

 

後來想到是不是一開始就沒有連線上呢?

經過認真思考,發現還真的是一開始就沒有連線上MongoDB的遠端伺服器,這才明白昨天並沒有根本上解決問題!!

真是個莫大的烏龍!

原來前面的語句只是將連線資訊等儲存起來罷了(詳細見Mongo_Client.py檔案(就是Pip安裝的那個pymongodb模組中的檔案))

直到:

jh.find_one({"姓名":"張三"})

這一語句時才真正去連線伺服器,這就是為什麼這個語句要執行等待一分鐘左右才最終報錯的原因。真是個大坑。

 

這意味著,mongoDB遠端伺服器其實根本就沒有被連線上,始終沒有解決問題。

決定明天只好開始佈置本地MongoDB資料庫服務了。

 

 

因為學習時間有限,今天的學習只能擱到這兒,還懇請高手能夠指點迷津,萬分感激。

 

——————————

今天整理的學習筆記完成,最後例行說明下我的自學思路:

根據過去多年我自學各種程式語言的經歷,認為只有真正體驗式,解決實際問題式的學習才會有真正的效果,即讓學習實際發生。在2004年的時候我開始在一個鄉村小學自學電腦 並學習vb6程式語言,沒有學習同伴,也沒有高師在上,甚至電腦都是孤島(鄉村那時還沒有網路),有的只是一本舊書,在痛苦的自學摸索中,我找到適應自己零基礎的學習方法:首先是每讀書的一小節就作相應的手寫筆記,第二步就是上機測試每一個筆記內容是否實現,其中會發現書中講的其實有出入或錯誤,第三步就是在上機測試之後,將筆記改為電子版,形成最終的修訂好的正確無誤的學習筆記 。

通過反覆嘗試錯誤,在那個沒有分享與交流的黑暗時期我摸黑學會了VB6,爾後接觸了其它語言,也曾聽過付費視訊課程,結果發現也許自己學歷果然太低,就算是零基礎的入門課程,其實也難以跟上進度,講師的教學多數出現對初學者的實際情況並不瞭解的情況,況且學習者的個體也存在差異呢?當然更可怕的是收費課程的價格往往是自己難以承受的。

於是我的所有程式設計學習都改為了自學,繼續自己的三步學習筆記法的學習之路。

當然自學的最大問題是會走那麼多的彎路,沒有導師直接輸入式的教學來得直接,好在網路給我們帶來無限搜尋的機會,大家在網路上的學習日誌帶給我們共享交流的機會,而QQ群等交流平臺、網路社群的成立,我們可以一起自學,互相批評交流,也可以獲得更有效,更自主的自學成果。

於是我以人生已過半的年齡,決定繼續我的程式設計自學之路,開始學習python,只希望與大家共同交流,一個人的獨行是可怕的,只有一群人的共同前進才是有希望的。

誠摯期待您的交流分享批評指點!歡迎聯絡我加入從零開始的自學聯盟。

這個時代網際網路成為了一種基礎設施的存在,於是本來在孤獨學習之路上的我們變得不再孤獨,因為網路就是一個新的客廳,我們時刻都可以進行沙龍活動。

非常樂意能與大家一起交流自己自學心得和發現,更希望大家能夠對我學習過程中的錯誤給予指點——是的,這樣我就能有許多免費的高師了——這也是分享時代,社群時代帶來的好福利,我相信大家會的,是吧!

 

根據完全共享的精神,開源互助的理念,我的個人自學錄製過程是全部按4K高清視訊錄製的,從手寫筆記到驗證手寫筆記的上機操作過程全程錄製,但因為4K高清檔案太大均超過5G以上,所以無法上傳至網路,如有需要可聯絡我QQ578652607對傳,樂意分享。上傳分享到百度網盤的只是壓縮後的720P的視訊。

 

我的學習過程錄影百度盤地址分享如下:(清晰度:1280x720)

 

連結:https://pan.baidu.com/s/1pxsntZ5bMRs1vr9uHSW7Fg

提取碼:u6mu

 

喜馬拉雅語音筆記:

https://www.ximalaya.com/keji/19103006/150385573

 

bilibili:

https://www.bilibili.com/video/av39921964/