摘要:例如它使用了一些黑科技來阻止用戶修改從數(shù)據(jù)庫查出的文檔。我發(fā)現(xiàn)我其實(shí)只需要的一小部分功能,于是我自己編寫了我對(duì)它的定位是一個(gè)輕量級(jí)無黑科技的它完成于年初,目前已被使用到了我的大部分個(gè)人項(xiàng)目中。
一開始我像很多人一樣使用 Mongoose 作為 ORM, 但時(shí)間長了我發(fā)現(xiàn)了 Mongoose 的一些不理想的地方。
Mongoose 通過定義 Setter 的方式記錄了對(duì)文檔的每一次修改,以便可以用 save 方法將文檔無沖突地儲(chǔ)存在數(shù)據(jù)庫中。但我在實(shí)際使用中發(fā)現(xiàn),我很少會(huì)使用這個(gè)功能,每當(dāng)對(duì)文檔進(jìn)行更新的時(shí)候,幾乎都是直接使用 MongoDB 的原子性操作符($set 等)。Mongoose 在這個(gè)功能上下了很大功夫,也增加了很多額外的約束。例如它 使用了一些黑科技 來阻止用戶修改從數(shù)據(jù)庫查出的文檔。而我希望從數(shù)據(jù)庫中查出文檔后進(jìn)行一些加工,向文檔上儲(chǔ)存一些額外的數(shù)據(jù)來供渲染頁面時(shí)使用(但不儲(chǔ)存到數(shù)據(jù)庫),本來我們?cè)?JavaScript 這樣的語言中是期待一個(gè)對(duì)象是可以被隨意修改的,但在 Mongoose 中卻不可以。
我發(fā)現(xiàn)我其實(shí)只需要 Mongoose 的一小部分功能,于是我自己編寫了 Mabolo, 我對(duì)它的定位是一個(gè)輕量級(jí)、無黑科技的 ORM. 它完成于 2015 年初,目前已被使用到了我的大部分個(gè)人項(xiàng)目中。
Mabolo 用 300 行代碼實(shí)現(xiàn)了一個(gè) ORM 最核心的一些功能:為數(shù)據(jù)集合定義字段的類型、驗(yàn)證文檔字段的合法性、定義類方法和實(shí)例方法、嵌入式的文檔和數(shù)組、原子性地更新整個(gè)文檔、同時(shí)兼容 Promise 和 callback 風(fēng)格的 API.
Mabolo 幾乎沒有使用什么黑科技,每個(gè) Model 都是一個(gè)普通的 JavaScript 構(gòu)造函數(shù),而每個(gè)文檔則都是由這個(gè)構(gòu)造函數(shù)生成的實(shí)例 —— 除了幾個(gè)用來保存內(nèi)部狀態(tài)的不可枚舉屬性之外和普通的對(duì)象沒有任何區(qū)別。
接下來我來談一談 Mabolo 中的幾個(gè)實(shí)現(xiàn)細(xì)節(jié)。
定義 Model在 Mongoose 中,要先創(chuàng)建 Mongoose 實(shí)例(即代表一個(gè)數(shù)據(jù)庫連接)才能根據(jù)它來創(chuàng)建 Model, 但這樣會(huì)造成 Model 定義依賴于這個(gè)全局的數(shù)據(jù)庫連接。而在 Mabolo 中,可以先創(chuàng)建與實(shí)例無關(guān)的 Model, 然后再將其綁定到 Mabolo 實(shí)例上:
User.coffee:
Mabolo = reuqire "mabolo" module.exports = Mabolo.model "User", name: String
app.coffee
Mabolo = reuqire "mabolo" mabolo = new Mabolo "mongodb://localhost/test" User = mabolo.bind require "./User"
即使 Model 還沒被綁定到 Mabolo 實(shí)例上,也是可以執(zhí)行查詢的,這些插件會(huì)被阻塞,直到 Model 被綁定到一個(gè)數(shù)據(jù)庫連接上。
實(shí)現(xiàn)上,Mabolo.model 會(huì)創(chuàng)建一個(gè)繼承(CoffeeScript 的 extends)自 AbstractModel 的類,作為 Model 來使用。在綁定時(shí),Mabolo.bind 會(huì)調(diào)用 Model 上的 bindCollection 函數(shù),這個(gè)函數(shù)會(huì) resolve 一個(gè)內(nèi)部的 Promise, 讓對(duì)數(shù)據(jù)庫的操作開始執(zhí)行。
嵌入式文檔Mabolo 中 Model 的字段定義,既可以是基本類型,也可以是另一個(gè) Model, 還可以是基本類型或 Model 的數(shù)組。
Token = mabolo.model "Token", code: String User = mabolo.model "User", tokens: [Token]
在保存文檔到數(shù)據(jù)庫時(shí),Mabolo 會(huì)調(diào)用 Model::transform 構(gòu)造字段定義中的嵌入式文檔,這樣才可以運(yùn)行定義在嵌入式文檔上的字段驗(yàn)證。而在從數(shù)據(jù)庫取出文檔時(shí),也會(huì)構(gòu)造字段定義中所描述的嵌入文檔, 以便用戶調(diào)用嵌入文檔上的實(shí)例方法。
下一步會(huì)支持在嵌入文檔上運(yùn)行 update 和 remove 方法。主要實(shí)現(xiàn)方法是 Model::transform 會(huì)在構(gòu)造出的嵌入文檔上儲(chǔ)存父文檔和在父文檔中的位置,以便 update 時(shí)為查詢和更新中的字段名加上前綴。
再之后會(huì)支持文檔中的引用關(guān)系,在從數(shù)據(jù)庫中取出文檔時(shí),Mabolo 會(huì)自動(dòng)取出被引用到的文檔,這個(gè)過程被稱為「填充」,用戶也可以自己定義更復(fù)雜的填充規(guī)則。
原子性地更新文檔Mabolo 使用了和 Mongoose 類似的技術(shù)來原子性地更新整個(gè)文檔,即在每次更新時(shí)都為文檔設(shè)置一個(gè)版本號(hào)(在 Mabolo 中是一個(gè)隨機(jī)的字符串),在進(jìn)行原子更新時(shí)會(huì)將當(dāng)前版本號(hào)作為一個(gè)查詢條件來運(yùn)行更新,如果沒有成功(版本號(hào)被另一個(gè)操作修改了),會(huì)從數(shù)據(jù)庫中查出最新的文檔,重放修改然后再一次嘗試提交。
user.modify (user) -> Q.delay(1000).then -> user.age = 19 .then ->
Mabolo 使用了一種更簡(jiǎn)單的方式實(shí)現(xiàn)重放修改 —— 即要求用戶傳入一個(gè)無副作用的修改函數(shù),這個(gè)函數(shù)會(huì)在每次重放修改的時(shí)候被調(diào)用一次。應(yīng)該說這只是一種不推薦大量使用的備選方案,更好的做法是直接使用 MongoDB 的原子操作符:
user.update $set: age: 19
https://jysperm.me/2015/06/mabolo-mongodb-orm/
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/18767.html
摘要:因?yàn)槁酚蓪用媸軜I(yè)務(wù)影響很大,經(jīng)常修改一些功能的行為,所以后來大部分測(cè)試都是針對(duì)層面的單元測(cè)試。在我了解的過程中,我發(fā)現(xiàn)中文網(wǎng)絡(luò)上對(duì)的討論非常分散,于是我創(chuàng)建了中文社區(qū),到年末已經(jīng)有個(gè)注冊(cè)用戶和個(gè)帖子了。 https://jysperm.me/2016/02/programming-of-2015/ 從 2014 年末開始開發(fā)的一個(gè)互聯(lián)網(wǎng)金融項(xiàng)目終于在今年三月份上線了,這是一個(gè) Node...
摘要:因?yàn)槁酚蓪用媸軜I(yè)務(wù)影響很大,經(jīng)常修改一些功能的行為,所以后來大部分測(cè)試都是針對(duì)層面的單元測(cè)試。在我了解的過程中,我發(fā)現(xiàn)中文網(wǎng)絡(luò)上對(duì)的討論非常分散,于是我創(chuàng)建了中文社區(qū),到年末已經(jīng)有個(gè)注冊(cè)用戶和個(gè)帖子了。 https://jysperm.me/2016/02/programming-of-2015/ 從 2014 年末開始開發(fā)的一個(gè)互聯(lián)網(wǎng)金融項(xiàng)目終于在今年三月份上線了,這是一個(gè) Node...
摘要:顧名思義,就是將關(guān)系型數(shù)據(jù)庫與中的對(duì)象關(guān)聯(lián)起來,提供了一種操作數(shù)據(jù)的簡(jiǎn)便方式,相當(dāng)于對(duì)數(shù)據(jù)庫加了一層更友好的接口。新增數(shù)據(jù)對(duì)象方法方法直接創(chuàng)建數(shù)據(jù)對(duì)象,需要調(diào)用方法保存到數(shù)據(jù)庫中。 咱們編程教室有不少同學(xué),學(xué)完了基礎(chǔ)課程,掌握了一定的編程能力,開始做項(xiàng)目了。然后很可能遇到一個(gè)問題:管理數(shù)據(jù)。課程里有講過用文件保存數(shù)據(jù),還有 pickle 、 csv 等模塊輔助。但對(duì)于稍微復(fù)雜一點(diǎn)的數(shù)據(jù)...
摘要:然后又介紹了基于的公號(hào)賬本應(yīng)用的數(shù)據(jù)庫設(shè)計(jì)。歡迎關(guān)注公號(hào)四月試用。 前兩篇 微信公號(hào)DIY 系列: 微信公號(hào)DIY:一小時(shí)搭建微信聊天機(jī)器人 微信公號(hào)DIY:訓(xùn)練聊天機(jī)器人&公號(hào)變身圖片上傳工具 介紹了如何使用搭建&訓(xùn)練聊天機(jī)器人以及讓公號(hào)支持圖片上傳到七牛,把公號(hào)變成一個(gè)七牛圖片上傳客戶端。這一篇將繼續(xù)開發(fā)公號(hào),讓公號(hào)變成一個(gè)更加實(shí)用的工具賬本(理財(cái)從記賬開始)。 代碼: 項(xiàng)目代...
閱讀 2399·2021-10-09 09:41
閱讀 3202·2021-09-26 09:46
閱讀 847·2021-09-03 10:34
閱讀 3187·2021-08-11 11:22
閱讀 3381·2019-08-30 14:12
閱讀 721·2019-08-26 11:34
閱讀 3354·2019-08-26 11:00
閱讀 1786·2019-08-26 10:26