<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          NoSQL | MongoDB入門實(shí)戰(zhàn)教程(7)

          共 3397字,需瀏覽 7分鐘

           ·

          2021-07-19 12:12

          【NoSQL| 總結(jié)/Edison Zhou

          前面我們學(xué)習(xí)了聚合查詢,本篇我們來看看在模型設(shè)計(jì)中如何應(yīng)用引用模式來提高查詢效率。

          1內(nèi)嵌模式

          在進(jìn)行MongoDB的模型設(shè)計(jì)中,基于JSON文檔模型,我們很容易就可以設(shè)計(jì)出一個(gè)內(nèi)嵌模式的文檔模型出來。

          可以不夸張地說,80%~90%的場景下,我們優(yōu)先都會(huì)使用內(nèi)嵌對(duì)象 或 內(nèi)嵌數(shù)組 的方式來設(shè)計(jì)文檔模型的所謂的1-1、1-N、N-N的關(guān)系。

          例如下面這個(gè)Contacts的文檔模型,它描述了一個(gè)聯(lián)系人的關(guān)系建模:

          Contacts
          { name: "Edison Zhou", company: "CSCEC YZW", title: ".NET Engineer", portraits: { mimetype: xxx, data: xxxx }, addresses: [ { type: home, … }, { type: work, … } ], groups: [    {name: "YZW Football Assocation" },    {name: "YZW .NET Assocation" } ]}

          可以看到,所謂的內(nèi)嵌類 其實(shí) 類似于 預(yù)先聚合(關(guān)聯(lián)),這樣的操作(引用+冗余)其實(shí)對(duì)讀操作更有性能優(yōu)勢。

          但是,內(nèi)嵌設(shè)計(jì)有一個(gè)大前提限制:即內(nèi)嵌后文檔大小不能超過16MB。

          此外,如果內(nèi)嵌的數(shù)組(通常是數(shù)組)的長度太大,比如數(shù)萬或更多的時(shí)候,也是不適合采用內(nèi)嵌模式的。

          那么,此時(shí)我們應(yīng)該怎么設(shè)計(jì)呢?

          2引用模式

          萬級(jí)長度的內(nèi)嵌數(shù)組

          這里我們?nèi)匀贿m用上面提到的Contacts模型,假設(shè)其中的groups是一個(gè)內(nèi)嵌數(shù)組,這個(gè)groups的數(shù)據(jù)可能有百萬級(jí)的長度,且每個(gè)Contacts文檔都需要冗余這么一份數(shù)據(jù),而且groups數(shù)據(jù)還面臨著頻繁修改的需求。

          Contacts
          { name: "Edison Zhou", company: "CSCEC YZW", title: ".NET Engineer", ......  // 假設(shè)下面groups有百萬級(jí),且一個(gè)group的信息改動(dòng)會(huì)引發(fā)百萬級(jí)的DB操作 groups: [ {name: "YZW Football Assocation" }, {name: "YZW .NET Assocation" } ]}

          適當(dāng)使用引用模式解決

          解決方案很簡單,就是針對(duì)groups使用單獨(dú)的collection來存儲(chǔ),在Contancts模型中添加對(duì)group id的集合的引用。

          Collection 1 - Contacts:

          Contacts
          { name: "Edison Zhou", company: "CSCEC YZW", title: ".NET Engineer", ...... // 假設(shè)下面groups有百萬級(jí),且一個(gè)group的信息改動(dòng)會(huì)引發(fā)百萬級(jí)的DB操作  group_ids: [1,2,3,4,5...]}

          Collection 2 - Groups:

          Groups
          { groups_id, name}

          這樣的設(shè)計(jì)其實(shí)類似于關(guān)系型數(shù)據(jù)庫模型的設(shè)計(jì),用Id來關(guān)聯(lián),我們再熟悉不過了。

          但是,在MQL中,我們就需要額外使用$lookup來實(shí)現(xiàn)類似SQL中的關(guān)聯(lián)查詢了,嚴(yán)格來說,應(yīng)該算是LEFT OUTER JOIN查詢。

          嗯,這又是一種聚合操作:

          db.Contacts.aggregate([{  $lookup:  {    from: "groups",    localField: "group_ids",    foreignField: "group_id",    as: "groups"  }}]);

          這個(gè)查詢會(huì)得到如下圖所示的結(jié)果:

          .NET中的Lookup操作:

          上面講解了如何通過MQL進(jìn)行操作,那么,在.NET中如何實(shí)現(xiàn)$lookup的效果呢?

          好在MongoDB Driver已經(jīng)幫我們提供了這樣的一個(gè)LookUp,且看下面的代碼示例:

          假設(shè)我們的實(shí)體定義如下:

          public class Contact{    [BsonId]    [BsonRepresentation(BsonType.ObjectId)]    public string Id { get; set; }
          public string Name { get; set; }
          public string Company { get; set; }
          public string Title { get; set; }
          public int[] GroupIds { get; set; }
          public IList<Group> Groups { get; set; }}
          public class Group{ [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; }
          public int GroupId { get; set; }
          public string Name { get; set; }}

          那么,可以通過Driver實(shí)現(xiàn)以下操作:

          public async Task<IList<Contact>> GetAsync(){    return await _contacts        .Aggregate()        .Lookup<Contact, Group, Contact>(            _groups,            local => local.GroupIds,            from => from.GroupId,            result => result.Groups)        .ToListAsync();}

          完整示例github地址:https://github.com/EdisonChou/EDT.Mongo.Sample

          運(yùn)行結(jié)果如下所示:

          什么時(shí)候使用引用模式

          綜上所述,當(dāng)滿足以下條件之一時(shí),你可以開始考慮引用模式設(shè)計(jì)文檔模型:

          (1)當(dāng)內(nèi)嵌后的文檔太大,有可能超過16MB限制的時(shí)候;

          (2)內(nèi)嵌的文檔 或 數(shù)組元素 有可能會(huì)頻繁修改的時(shí)候;

          (3)內(nèi)嵌數(shù)組元素 有可能會(huì)持續(xù)增長且沒有封頂?shù)臅r(shí)候;

          引用模式設(shè)計(jì)的限制

          引用模式也并非銀彈,它存在以下一些限制:

          (1)MongoDB對(duì)于使用引用的集合之間沒有所謂的外鍵檢查;

          (2)MongoDB使用聚合框架的$lookup來模仿關(guān)聯(lián)查詢;

          (3)$lookup只支持LEFT OUTER JOIN,且關(guān)聯(lián)目標(biāo)(from)不能是分片表;

          db.Contacts.aggregate([{  $lookup:  {    from"groups"// 這里的from不能是分片表    ......  }}]);
          End總結(jié)

          本文簡單介紹了MongoDB的模型設(shè)計(jì)中的內(nèi)嵌模式和引用模式,探討了引用模式的使用、何時(shí)使用 及 使用限制。

          下一篇,我們會(huì)學(xué)習(xí)MongoDB的模式設(shè)計(jì)中的一些設(shè)計(jì)模式并套用這些設(shè)計(jì)模式簡化設(shè)計(jì)難度。


          參考資料

          唐建法,《MongoDB高手課》(極客時(shí)間)

          郭遠(yuǎn)威,《MongoDB實(shí)戰(zhàn)指南》(圖書)

          △推薦訂閱學(xué)習(xí)

          歡迎各位讀者加入微信群一起學(xué)習(xí)交流,
          在公眾號(hào)后臺(tái)回復(fù)“加群”即可~~

          ?

          ?

          瀏覽 67
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久人97 | 性爱视频网址 | 天堂精品在线 | 奇米影视一区 | 国产av一区二区三本 |