mongodb中文檔id生成原理以及mock方法

用過Mongodb 的同學(xué)都知道护昧,它會默認(rèn)為每個(gè) 文檔(document) 生成一個(gè)ObjectId類型_id字段蹈矮。而且很多時(shí)候吼旧,在構(gòu)建rest api的時(shí)候,都會用該字段來標(biāo)識資源秉继。比如:訪問具體一篇博文的內(nèi)容,URL就可能是:/posts/:postId泽铛,這里:postId就是直接用_id字段的字符串形式來表示尚辑。它通常會是這樣一串值:** 538f0231d74805ed36fc30db**。

那么當(dāng)我們在對rest api服務(wù)做測試的時(shí)候盔腔,就需要來模擬這樣的id腌巾,而且它必須有效的。什么意思呢铲觉?我來舉個(gè)例子:假設(shè)我們要對查看博文這個(gè)api做測試澈蝙,那么其中就可能會有這樣兩條用例:

  1. 當(dāng)postId不合法時(shí),服務(wù)器應(yīng)該返回處理錯(cuò)誤
  2. 當(dāng)postId合法但不存在時(shí)撵幽,服務(wù)器應(yīng)該返回處理成功并返回0條記錄

其中灯荧,第1條用例我們在測試的時(shí)候,可以很簡單地模擬一個(gè)無效的postId盐杂,比如:12345 這樣的就可以了逗载。但是對于第2條,我們則必須要模擬一個(gè)有效的id链烈,它是可以通過mongodb合法性校驗(yàn)的厉斟,但是呢mongodb利用這個(gè)id去數(shù)據(jù)庫中尋找時(shí)又是找不到對應(yīng)記錄的。

為了達(dá)到這樣一個(gè)目的强衡,我們必須得要知道id到底是如何生成出來的擦秽,這樣我們就可以模擬出符合要求的id了。

好漩勤,開干吧感挥!既然說id是個(gè)ObjectId類型的,那么我們先去搞清楚ObjectId這種類型到底是什么東西越败,通過Mongodb官方文檔 了解到ObjectId其實(shí)就是12個(gè)字節(jié)長的BSON 触幼。其中12個(gè)字節(jié)具體內(nèi)容為:

如上圖所示,12個(gè)字節(jié)被拆成4個(gè)部分究飞,每個(gè)部分都很好理解置谦,無需多做解釋堂鲤。這里唯一要提的一點(diǎn)是其具體的實(shí)現(xiàn)是根據(jù)mongodb驅(qū)動(dòng)器(driver)的。下面是node版本驅(qū)動(dòng)器 中對于objectid生成部分的實(shí)現(xiàn)代碼(具體實(shí)現(xiàn)見js-bson 中的generate方法):

ObjectID.prototype.generate = function(time) {
  if ('number' != typeof time) {
    time = parseInt(Date.now()/1000,10);
  }
  
  var time4Bytes = BinaryParser.encodeInt(time, 32, true, true);
  /* for time-based ObjectID the bytes following the time will be zeroed */
  var machine3Bytes = BinaryParser.encodeInt(MACHINE_ID, 24, false);
  var pid2Bytes = BinaryParser.fromShort(typeof process === 'undefined' ? Math.floor(Math.random() * 100000) : process.pid);
  var index3Bytes = BinaryParser.encodeInt(this.get_inc(), 24, false, true);

  return time4Bytes + machine3Bytes + pid2Bytes + index3Bytes;
};

這里的MACHINE_ID就直接采用了隨機(jī)數(shù)媒峡,而其他的驅(qū)動(dòng)器則采用了md5值瘟栖。接下來,我們再來看看encodeInt方法:

BinaryParser.encodeInt = function encodeInt (data, bits, signed, forceBigEndian) {
    var max = maxBits[bits];

  if (data >= max || data < -(max / 2)) {
    this.warn("encodeInt::overflow");
    data = 0;
  }

    if (data < 0) {
    data += max;
  }

    for (var r = []; data; r[r.length] = String.fromCharCode(data % 256), data = Math.floor(data / 256));

    for (bits = -(-bits >> 3) - r.length; bits--; r[r.length] = "\0");

  return ((this.bigEndian || forceBigEndian) ? r.reverse() : r).join("");
};

該方法其實(shí)最終就會返回bits位字符串丝蹭。那么此前的generate方法就是會返回一個(gè)包含12個(gè)字符的字符串慢宗。所以這其實(shí)就是ObjectId內(nèi)部的表現(xiàn)形式。我們接著繼續(xù)看mongodb的文檔 發(fā)現(xiàn)ObjectId的對外字符串表現(xiàn)形式其實(shí)是一個(gè)16進(jìn)制的字符串奔穿,那么字符串長度是多少呢镜沽?這里簡單做換算就可以了:1個(gè)字節(jié)需要2位16進(jìn)制來表示,那么12個(gè)字節(jié)就是24位贱田。所以這個(gè)長度一定是24缅茉。

好了,那么歸根結(jié)底男摧,一個(gè)合法的id字符串表現(xiàn)形式其實(shí)就是:一個(gè)由16進(jìn)制數(shù)字組成的長度為24的字符串蔬墩。

了解了這個(gè)原理,那要mock一個(gè)id就輕而易舉了耗拓。這里推薦一個(gè)名為chancejs的隨機(jī)數(shù)據(jù)生成工具拇颅,利用chance.hash({ length: 24 });就可以了!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末乔询,一起剝皮案震驚了整個(gè)濱河市樟插,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌竿刁,老刑警劉巖黄锤,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異食拜,居然都是意外死亡鸵熟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門负甸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來流强,“玉大人,你說我怎么就攤上這事惑惶≈笈危” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵带污,是天一觀的道長。 經(jīng)常有香客問我香到,道長鱼冀,這世上最難降的妖魔是什么报破? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮千绪,結(jié)果婚禮上充易,老公的妹妹穿的比我還像新娘。我一直安慰自己荸型,他們只是感情好盹靴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瑞妇,像睡著了一般稿静。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辕狰,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天改备,我揣著相機(jī)與錄音,去河邊找鬼蔓倍。 笑死悬钳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的偶翅。 我是一名探鬼主播默勾,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼聚谁!你這毒婦竟也來了母剥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤垦巴,失蹤者是張志新(化名)和其女友劉穎媳搪,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骤宣,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡秦爆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了憔披。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片等限。...
    茶點(diǎn)故事閱讀 40,015評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖芬膝,靈堂內(nèi)的尸體忽然破棺而出望门,到底是詐尸還是另有隱情,我是刑警寧澤锰霜,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布筹误,位于F島的核電站,受9級特大地震影響癣缅,放射性物質(zhì)發(fā)生泄漏厨剪。R本人自食惡果不足惜哄酝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望祷膳。 院中可真熱鬧陶衅,春花似錦、人聲如沸直晨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勇皇。三九已至罩句,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間儒士,已是汗流浹背的止。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留着撩,地道東北人诅福。 一個(gè)月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像拖叙,于是被迫代替她去往敵國和親氓润。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容