有没 Java 开源包能在 MongoDB 上跑 SQL 吗?
MongoDB 本身不支持的 SQL 功能,现有开源 MongoDB JDBC 驱动程序工作原理是 SQL 查询经过验证并转换为 MongoDB 查询,然后调用 MongoDB Java API 执行,即提供了 SQL 到 MongoDB 查询语言的翻译工具和服务。而 MongoDB 里是多层嵌套的结构,属性字段任意出现,光是描述清楚选取哪一层的哪些字段信息,都是件不容易的事,开源的 MongoDB JDBC 驱动程序只支持简单 SQL,不支持字段表达式、不支持嵌套查询、不支持关联查询等常见的 SQL 用法,很难在实际工作中投入使用。其实如果使用Open-esProc计算包,先通过 MongoDB 简单查询,再结合 Open-esProc 内置 SPL 语法(类 SQL 的计算),不仅能完成 SQL 的全部功能,而且特别擅长处理多层数据。
先举个简单的例子说明如何使用 SPL。比如,MongoDB 有名为 test1 的 collection,用来存储员工信息,Orders 字段为数组类型,用来存储当前员工的多个订单。部分数据如下:
[{
"_id": {"$oid": "6074f6c7e85e8d46400dc4a7"},
"EId": 7,"State": "Illinois","Dept": "Sales","Name": "Alexis","Gender": "F","Salary": 9000,"Birthday": "1972-08-16",
"Orders": [
{"OrderID": 70,"Client": "DSG","SellerId": 7,"Amount": 288,"OrderDate": "2009-09-30"},
{"OrderID": 131,"Client": "FOL","SellerId": 7,"Amount": 103.2,"OrderDate": "2009-12-10"}
]
}
{
"_id": {"$oid": "6074f6c7e85e8d46400dc4a8"},
"EId": 8,"State": "California", ...
}]
用 SPL 对多层 collection 进行条件查询:
A |
|
1 |
=mongo_open("mongodb://127.0.0.1:27017/mongo") |
2 |
=mongo_shell(A1,"test1.find()") |
3 |
=A2.conj(Orders) |
4 |
=A3.select(Amount>1000 && Amount<=3000 && like@c(Client,"*s*")).fetch() |
5 |
=mongo_close(A1) |
从A2可以看出来,SPL支持MongoDB的json查询表达式(find、count、distinct和aggregate),比如区间查询写作:=mongo_shell(A2,"test1.find({Orders.Amount:{$gt:1000,$lt:3000}})")。
上述 SPL 代码是在esProc IDE中调试并执行的,将其存为脚本文件(比如select.dfx),和 Java 程序部署在一起,然后通过JDBC接口在JAVA中调用,具体如下:
package Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class test1 {
public static void main(String[] args)throws Exception {
Class.forName("com.esproc.jdbc.InternalDriver");
Connection connection =DriverManager.getConnection("jdbc:esproc:local://");
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery("call select()");
……
if(connection != null) connection.close();
}
}
类似地,用 SPL 实现分组汇总代码如下:
A |
|
1 |
=mongo_open("mongodb://127.0.0.1:27017/mongo") |
2 |
=mongo_shell(A1,"test1.find()") |
3 |
=A2.conj(Orders).groups(year(OrderDate);sum(Amount)) |
4 |
=mongo_close(A1) |
关联查询代码如下:
A |
|
1 |
=mongo_open("mongodb://127.0.0.1:27017/mongo") |
2 |
=mongo_shell(A1,"test1.find()") |
3 |
=A2.new(Orders.OrderID,Orders.Client, Name,Gender,Dept).fetch() |
4 |
=mongo_close(A1) |
SPL 的数据结构本身就是多层的,可以直接对应多层的 collection,可以天然表达主子关系,如此一来就不必再额外进行关联。
两个单层 collection 关联用 SPL 也很简单:
A |
|
1 |
=mongo_open("mongodb://127.0.0.1:27017/mongo") |
2 |
=mongo_shell(A1,"Orders.find()").fetch() |
3 |
=mongo_shell(A1,"Employees.find()").fetch() |
4 |
=mongo_close(A1) |
5 |
=join(A2,SellerId;A3,EId) |
6 |
=A5.new(_1.OrderID,_1.Client,_2.Name,_2.Gender,_2.Dept) |
SPL表达形式多样,除了本身的过程化语法,还支持SQL语法。因为SQL数据类型不支持多层数据,所以只支持两个单层collection的关联,代码如下:
A |
|
1 |
=mongo_open("mongodb://127.0.0.1:27017/mongo") |
2 |
=mongo_shell(A34,"Orders.find()").fetch() |
3 |
=mongo_shell(A34,"Employees.find()").fetch() |
4 |
=mongo_close(A34) |
5 |
$select o.OrderId,o.Client,e.Name,e.Gender,e.Dept from {A35} o join {A36} e on o.SellerId=e.EId |
更多 MongoDB 复杂计算示例,参考 辅助 MongoDB 计算 ,与 Java 程序集成,详情参考 Java 如何调用 SPL 脚本