簡化 MongoDB 關聯運算

【摘要】
MongoDB提供的 lookup 對多表關聯實現了基本的支持,但面對一些比較複雜的關聯狀況,每每會遇到 shell 腳本過於複雜的問題。而集算器 SPL 語言,則因其離散性、易用性剛好能彌補 Mongo 這方面的不足。若想了解更多,請前往乾學院:簡化 MongoDB 關聯運算!
MongoDB屬於 NoSql 中的基於分佈式文件存儲的文檔型數據庫,這種bson格式的文檔結構,更加貼近咱們對物體各方面的屬性描述。而在使用 MongoDB 存儲數據的過程當中,有時候不免須要進行關聯表查詢。自從 MongoDB 3.2 版本後,它提供了 $lookup 進行關聯表查詢,讓查詢功能改進了很多。但在實現應用場景中,所遇到的環境錯綜複雜,問題解決也非易事,腳本書寫起來也並不簡單。好在有了集算器 SPL 語言的協助,處理起來就相對容易多了。 java

        本文咱們將針對 MongoDB 在關聯運算方面的問題進行討論分析,並經過集算器 SPL 語言加以改進,方便用戶使用 MongoDB。討論將分爲如下幾個部分:
1. 關聯嵌套結構狀況 1…………………………………………….. 1
2. 關聯嵌套結構狀況 2…………………………………………….. 3
3. 關聯嵌套結構狀況 3…………………………………………….. 4
4. 兩表關聯查詢………………………………………………………. 6
5. 多表關聯查詢………………………………………………………. 8
6. 關聯表中的數組查找…………………………………………… 10
Java 應用程序調用 DFX 腳本…………………………………… 12mongodb

1.關聯嵌套結構狀況 1

兩個關聯表,表 A 與表 B 中的內嵌文檔信息關聯, 且返回的信息在內嵌文檔中。表 childsgroup 字段childs是嵌套數組結構,須要合併的信息 name 在其下。shell

測試數據:數據庫

history:數組

image.png

childsgroup:數據結構

image.png

表History中的child_id與表childsgroup中的childs.id關聯,但願獲得下面結果:分佈式

{函數

    "_id" : ObjectId("5bab2ae8ab2f1bdb4f434bc3"),post

    "id" : "001",學習

    "history" : "today worked",

    "child_id" : "ch001",

    "childInfo" :

    {

         "name" : "a",

        "mobile" : 1111

    }

   ………………

}

Mongo 腳本

image.png

       這個腳本用了幾個函數lookup、pipeline、match、unwind、replaceRoot處理,通常 mongodb 用戶不容易寫出這樣複雜腳本;那麼咱們再看看 spl 腳本是如何實現的:

SPL腳本 ( 文件名:childsgroup.dfx)

image.png

關聯查詢結果:

image.png

腳本說明:
       A1:鏈接 mongodb 數據庫。
       A2:獲取 history 表中的數據。
       A3:獲取 childsgroup 表中的數據。
       A4:將 childsgroup 中的 childs 數據提取出來合併成序表。
       A5:表 history 中的 child_id 與表 childs 中的 id 關聯查詢,追加 info 字段, 返回序表。
       A6:關閉數據庫鏈接。

       相對 mongodb 腳本寫法,SPL 腳本的難度下降了很多,思路也更加清晰,也不須要再去熟悉有關 mongo 函數的用法,以及如何去組合處理數據等,節約了很多時間。

2.關聯嵌套結構狀況 2

兩個關聯表,表 A 與表 B 中的內嵌文檔信息關聯, 將信息合併到內嵌文檔中。表 txtPost 字段 comment 是嵌套數組結構,須要把 comment_content 合併到其下。

txtComment:

image.png

txtPost

image.png

指望結果:

image.png

Mongo 腳本

image.png

表txtPost 按 comment 拆解成記錄,而後與表 txtComment 關聯查詢,將其結果放到數組中,再將數組拆解成記錄,將comment_content 值移到 comment 下,最後分組合並。

SPL 腳本:

image.png

關聯查詢結果:

image.png

腳本說明:
      A1:鏈接 mongodb 數據庫。
      A2:獲取 txtPost 表中的數據。
      A3:獲取 txtComment 表中的數據。
      A4:將序表 A2 下的 comment 與 post_no 組合成序表,其中 post_no 更名爲 pno。
      A5:序表 A4 經過 comment_no 與序表 A3 關聯,追加字段 comment_content,將其更名爲 Content。
      A6:按 pno 分組返回序表,~ 表示當前記錄。
      A7:關閉數據庫鏈接。

      Mongo、SPL 腳本實現方式相似,都是把嵌套結構的數據轉換成行列結構的數據,再分組合並。但 SPL 腳本的實現更簡單明瞭。

3.關聯嵌套結構狀況 3

兩個關聯表,表 A 與表 B 中的內嵌文檔信息關聯, 且返回的信息在記錄上。表collection2字段product是嵌套數組結構,返回的信息是isCompleted等字段。

測試數據:
collection1:
{
   _id: '5bc2e44a106342152cd83e97',
   description
    {
      status: 'Good',
      machine: 'X'
     },
   order: 'A',
   lot: '1'
   };
  
collection2:
{
   _id: '5bc2e44a106342152cd83e80',
   isCompleted: false,
   serialNo: '1',
   batchNo: '2',
   product: [ // note the subdocuments here
        {order: 'A', lot: '1'},
        {order: 'A', lot: '2'}
    ]
}

期待結果
{
   _id: 5bc2e44a106342152cd83e97,
   description:
       {
         status: 'Good',
         machine: 'X',
       },
   order: 'A',
   lot: '1' ,
   isCompleted: false,
   serialNo: '1',
   batchNo: '2'
}

Mongo 腳本

image.png

lookup 兩表關聯查詢,首個 addFields獲取isCompleted數組的第一個記錄,後一個addFields 轉換成所須要的幾個字段信息

SPL腳本:

image.png

腳本說明:
      A1:鏈接 mongodb 數據庫。
      A2:獲取 collection1 表中的數據。
      A3:獲取 collection2 表中的數據。
      A4:根據條件 order, lot 從序表 A2 中查詢記錄,而後追加序表 A3 中的字段 serialNo, batchNo,返回合併後的序表。
      A5:關閉數據庫鏈接。

      Mongo、SPL 腳本都實現了預期的結果。SPL 很清晰地實現了從數據記錄中的內嵌結構中篩選,將符合條件的數據合併成新序表。

4.兩表關聯查詢

從關聯表中選擇所須要的字段組合成新表。

Collection1:

image.png

  collection2:

image.png

指望結果:

image.png

Mongo 腳本

image.png

lookup 兩表進行關聯查詢,redact 對記錄根據條件進行遍歷處理,project 選擇要顯示的字段。

SPL腳本:

image.png

腳本說明:
      A1:鏈接 mongodb 數據庫。
      A2:獲取c1表中的數據。
      A3:獲取c2表中的數據。
      A4:兩表按字段 user1,user2 關聯,追加序表 A3 中的 output 字段,返回序表。
      A5:關閉數據庫鏈接。

      Mongo、SPL 腳本都實現了預期的結果。SPL 經過 join 把兩個關聯表不一樣的字段合併成新表,與關係數據庫用法相似。

5.多表關聯查詢

多於兩個表的關聯查詢,結合成一張大表。

Doc1:

image.png

  Doc2:

image.png

  Doc3:

image.png

合併後的結果:
{
    "_id" : ObjectId("5901a4c63541b7d5d3293766"),
    "firstName" : "shubham",
    "lastName" : "verma",
    "address" : {
        "address" : "Gurgaon"
    },
    "social" : {
        "fbURLs" : "http://www.facebook.com",
        "twitterURLs" : "http://www.twitter.com"
    }
}

Mongo 腳本

image.png

      因爲 Mongodb 數據結構緣由,寫法也多樣化,展現也各不相同。

SPL腳本:

image.png

      Mongo、SPL 腳本都實現了預期的結果。此 SPL 腳本與上面例子相似,只是多了一個關聯表,每次 join 就新增長字段,最後疊加構成一張大表。

      SPL 腳本的簡潔性、統一性很是明顯。

6.關聯表中的數組查找

從關聯表記錄數據組中查找符合條件的記錄, 用給定的字段組合成新表。

測試數據:

users:

image.png

workouts:

image.png

指望結果:

image.png

Mongo 腳本

image.png

把關聯表 users,workouts 查詢結果放到數組中,再將數組拆解,提高子記錄的位置,去掉不須要的字段。  

SPL腳本 (users.dfx):

image.png

腳本說明:
      A1:鏈接 mongodb 數據庫。
      A2:獲取users表中的數據。
      A3:獲取workouts表中的數據。
      A4:查詢序表 A3 的 _id 值存在於序表A2中 workouts 數組的記錄, 並追加 name 字段。返回合併的序表。
      A5:關閉數據庫鏈接。
      因爲須要獲取序列的交集不爲空爲條件,故將 _id 轉換成序列。
      Mongo、SPL 腳本都實現了預期的結果。從腳本實現過程來看,SPL 集成度高而又不失靈活性,讓程序簡化了很多。

7.Java 應用程序調用 DFX 腳本

      在經過 SPL 腳本對 MongoDB 數據進行了關聯計算後,其結果能夠被 java 應用程序很容易地使用。集算器提供了 JDBC 驅動程序,用 JDBC 存儲過程方式訪問,與調用存儲過程相同。(JDBC 具體配置參考《集算器教程》中的「JDBC基本使用」章節)

   Java調用主要過程以下:

   public void testUsers(){

       Connection con = null;

       com.esproc.jdbc.InternalCStatement st;

       try{

         //創建鏈接

         Class.forName("com.esproc.jdbc.InternalDriver");

         con= DriverManager.getConnection("jdbc:esproc:local://");

         //調用存儲過程,其中 users是 dfx 的文件名

         st =(com. esproc.jdbc.InternalCStatement)con.prepareCall("call users> ()");

         //執行存儲過程

         st.execute();

         //獲取結果集

         ResultSet rs = st.getResultSet();

          。。。。。。。

   catch(Exception e){

         System.out.println(e);

   }

       能夠看到,使用時按標準的 JDBC 方法操做,集算器很方便嵌入到 Java 應用程序中。同時,集算器也支持 ODBC 驅動,所以集成到其它支持 ODBC 的語言也很是容易。

       Mongo 存儲的數據結構相對關係數據庫更復雜、更靈活,其提供的查詢語言也很是強、適應面廣,同時須要瞭解函數也很多,函數之間的結合更是變化多端,所以要熟練掌握並應用也並不是易事。集算器的離散性、易用性剛好能彌補 Mongo 這方面的不足,在下降 mongo 學習成本及使用複雜度、難度的同時,讓 mongo 的功能獲得更充分的展示。

相關文章
相關標籤/搜索