Java 怎样在 MongoDB 上做 JOIN
用MongoDB官方的查询语言就可以做join,但只能用$lookup函数实现left jon,其他类型的连接就要在$lookup的基础上自行修改了,而且很难改出来cross join。另外,官方json风格的语法很复杂,既难用又啰嗦。
用支持通用SQL的Calcite也可以做join,而且各种连接类型都支持得不错,但Calcite整体计算能力很差,连模糊查询和日期函数都没有。Calcite也不支持多层collection里的自然连接,除非提前改造成多个单层collection。
更好的方法是用开源类库集算器SPL,既能用简单方便的函数做各种join,也支持多层collection里的自然关联,而且整体计算能力很强。
SPL提供了join函数做连接,用法简单直观。比如2个collection是主子关系,都有相同的字段cat,要实现内连接再进行分组汇总,可以先编写SPL脚本文件:
A |
B |
|
1 |
=mongo_open("mongodb://127.0.0.1:27017/mongo") |
|
2 |
=mongo_shell(A1,"main.find()").fetch() |
=mongo_shell@x(A1,"detail.find()").fethc() |
3 |
=join@1(B2,cat;A2,cat) |
|
4 |
=A3.groups(_1.title, _2.path; sum(_1.amount)) |
再在JAVA中通过JDBC调用脚本文件名:
…
Class.forName("com.esproc.jdbc.InternalDriver");
Connection connection =DriverManager.getConnection("jdbc:esproc:local://");
Statement statement = connection.createStatement();
String str="call leftjoin()";
ResultSet result = statement.executeQuery(str);
…
SPL支持各种类型的连接,学习起来毫无难度。上面的join表示是内关联,表示左关联时只需写成join@1,其中@1是函数选项;类似地,全连接写成join@f。cross join比较特殊,SPL特意用函数xjoin来表示。
SPL支持SQL语法做关联,方便数据库程序员使用。比如左关联可以改写成:
A |
B |
|
1 |
=mongo_open("mongodb://127.0.0.1:27017/mongo") |
|
2 |
=mongo_shell(A1,"main.find()").fetch() |
=mongo_shell@x(A1,"detail.find()").fethc() |
3 |
$select d.title, m.path,sum(d.amount) from {B2} as d left join {A2} as m on d.cat=m.cat group by d.title, m.path |
关于更多的SPL SQL语法,可了解《在文件上使用 SQL 查询的示例》
SPL支持多层collection的自然连接,代码非常简单,而且执行效率高。比如某collection存储多条雇员记录,每个雇员的Orders字段存储多条订单记录,对雇员和订单进行自然关联,只须如下代码:
A |
|
1 |
=mongo_open("mongodb://127.0.0.1:27017/mongo") |
2 |
=mongo_shell@x(A1,"data.find()").fetch() |
3 |
=A2.new(Orders.Client:Client, Orders.Amount:Amount, Name, Dept, Salary) |
SPL可以把计算代码直接写在JAVA中。这种写法适合代码简短或很少修改的情况,虽然方便,但要比脚本文件的耦合性高。比如多层collection的自然连接可以改写为:
…
Class.forName("com.esproc.jdbc.InternalDriver");
Connection connection =DriverManager.getConnection("jdbc:esproc:local://");
Statement statement = connection.createStatement();
String str="=mongo_open(\"mongodb://127.0.0.1:27017/mongo\"). mongo_shell@x(A1,\"data.find()\").fetch().new(Orders.Client:Client, Orders.Amount:Amount, Name, Dept, Salary)";
ResultSet result = statement.executeQuery(str);
…
SPL也支持其他数据源和MongoDB做join,比如restful\数据库\文件\各类NoSQL。下面以数据库为例:
A |
B |
|
1 |
=mongo_open("mongodb://127.0.0.1:27017/mongo") |
|
2 |
=mongo_shell@x(A1,"main.find()").fetch() |
=connect("orcl").query@x("select * from detail") |
3 |
=join@1(B2,cat;A2,cat) |
|
4 |
=A3.groups(_1.title, _2.path; sum(_1.amount)) |
对于逻辑较复杂的计算,SPL提供了专用的IDE进行编辑调试,不仅具备完整调试功能,还可随时观察每一步的计算结果:
除了计算能力强、语法简单易学等特点,SPL还支持大数据量关联和高性能关联,这里不再赘述。