多樣性資料源是報表開發的常見問題,但用JasperReport等報表工具本身難以處理,比如展現兩個MongoDB collection連接配接的結果。雖然JasperReport有virtual data source或table join,但這些功能隻在商業版或高端版本出現,在免費版中實作的難度很大。而且這些功能隻支援兩個資料源的連接配接,要實作多連接配接則麻煩得多。另外,這些功能隻是圖形化界面,無法對連接配接後的資料進行類似SQL的結構化計算。
集算器具有結構化強計算引擎,支援多樣性資料源,內建簡單,可以協助報表工具友善地實作此類需求。下面通過一個例子來說明MongoDB join的實作過程。
Sales和emp是MongoDB中的兩個collection,sales中的字段SellerId邏輯上相當于外鍵,指向emp的EId字段,現在需要按時間段查詢出sales中的訂單,并和emp進行左連接配接,最後在報表中展現。部分源資料如下:
Collection sales

Collectionemp
集算器腳本:
A1=MongoDB("mongo://localhost:27017/test?user=root&password=sa")
上述代碼用來建立MongoDB的資料庫連接配接,可用user和password來指定使用者名和密碼。
集算器也支援用JDBC方式連接配接MongoDB,用法和普通資料庫一樣,但由于第三方JDBC不僅收費,而且功能上不如官方庫函數,比如無法擷取多層資料,是以集算器直接封裝原生方法,MongoDB的功能和文法都被保留,比如可以在此基礎上使用find函數,
A2=A1.find("sales","{'$and':[{'OrderDate':{'$gte':'"+string(begin)+"'}},{'OrderDate':{'$lte':'"+string(end)+"'}}]}","{_id:0}").fetch()
上述代碼從MongoDB的salescollection中查詢出某時間段的記錄。函數find的第一個參數是collection名,第二個參數是查詢條件,遵循MongoDB規範,第三個參數限定傳回的字段。注意查詢條件中的begin和end是來自報表的外部參數,分别表示OrderDate的起始時間和終止時間。
函數find傳回的是遊标,并不會把資料直接讀入記憶體,是以支援大資料量。可以用skip、sort、conj等函數繼續操作遊标,直到遇到函數fetch、groups,或語句for時才會真正取數。本例直接用函數fetch()将資料讀入記憶體,假如時間段是2009-01-01到2009-12-31,則A2的計算結果如下:
A3=A1.find("emp",,"{_id:0}").fetch()
上述代碼從emp collection取數,無條件,除了_id之外取出所有字段,結果如下:
A4=A1.close()
上述代碼用來關閉A1中的資料庫連接配接。
[email protected](A2:sales,SellerId;A3:emp,EId)
上述代碼将A2和A3進行左連接配接,連接配接字段是A2的SellerId和A3 的Eld,直覺起見,連接配接後的兩部分資料分别命名為sales和emp。函數join執行連接配接計算,選項@1表示左連接配接,計算結果如下圖左側:
可以看到,由于是左連接配接,是以sales中部分SellerId無法在emp中找到對應的記錄。如果想進行全連接配接,可以使用選項@f,無選項則表示内連接配接。
A6=A5.new(sales.OrderID:OrderID,sales.Client:Client,sales.Amount:Amount,sales.OrderDate:OrderDate,emp.Name:Name,emp.Dept:Dept,emp.Gender:Gender)
A5執行連接配接操作,A6則從連接配接的結果中取出需要的字段,并用函數new組成二維表。比如sales.OrderID:OrderID表示從A5取出sales.OrderID字段,重命名為OrderID(報表工具無法識别sales.OrderID這樣的字段名)。計算結果如下:
到此為止,報表需要的資料就全部計算出來了。最後隻需用result A6将A6中的二維表傳回報表工具。集算器對外提供JDBC接口,報表工具會将集算器識别為普通資料庫,內建方案請參考相關文檔。
接下來以JasperReport為例設計報表,表樣如下:
需要定義兩個報表參數Pbegin、Pend,分别對應集算器中的兩個參數。預覽後可以看到報表結果:
報表調用集算器的方法和調用存儲過程一樣,比如将本腳本儲存為mongodbJoin.dfx,則在JasperReport的SQL設計器中可以用mongodbJoin $P{pbegin},$P{pend}來調用。