用 Java 如何对 MongoDB 执行类似 SQL 的查询?
解决办法:esProc - Java 专业计算包
esProc 是专门用于基于 Java 计算的类库,旨在简化 Java 代码。 SPL 是基于 esProc 计算包的脚本语言,和 Java 程序一起部署,可以理解为库外存储过程,用法和 Java 程序中调用存储过程相同,通过 JDBC 接口传递给 Java 程序执行,实现结构化计算。它非常轻巧,语法简单,类似执行 SQL 的方式,查询 MongoDB 数据。
比如,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}})")。
上述代码可在esProc IDE中执行,存为脚本文件(比如select.dfx),通过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();
}
}
与 Java 程序集成,详情参考 Java 如何调用 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。
两个单层 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的特色是多层数据,用json表达式计算多层数据会遇到很多困难,这种情况下用 SPL 经常可以简化计算。比如:统计下面每条记录中 income,output 的数量之和。
_id |
income |
output |
1 |
{"cpu":1000, "mem":500, "mouse":"100"} |
{"cpu":1000, "mem":600 ,"mouse":"120"} |
2 |
{"cpu":2000,"mem":1000, "mouse":"50","mainboard":500 } |
{"cpu":1500, "mem":300} |
用json表达式计算时,代码很繁琐:
var fields = [ "income", "output"];
db.computer.aggregate([
{
$project:{
"values":{
$filter:{
input:{
"$objectToArray":"$$ROOT"
},
cond:{
$in:[
"$$this.k",
fields
]
}
}
}
}
},
{
$unwind:"$values"
},
{
$project:{
key:"$values.k",
values:{
"$sum":{
"$let":{
"vars":{
"item":{
"$objectToArray":"$values.v"
}
},
"in":"$$item.v"
}
}
}
}
},
{$sort: {"_id":-1}},
{ "$group": {
"_id": "$_id",
'income':{"$first": "$values"},
"output":{"$last": "$values"}
}},
]);
用 SPL 计算就简单多了:
A |
|
1 |
=mongo_open("mongodb://127.0.0.1:27017/raqdb") |
2 |
=mongo_shell(A1,"computer.find()").fetch() |
3 |
=A2.new(_id:ID,income.array().sum():INCOME,output.array().sum():OUTPUT) |
4 |
>A1.close() |
说下esProc IDE的配置。在Extend library中启用MongoCli即可完成配置,配置时可用图形界面。
参考以下内容在 java 应用程序中连接 MongoDB:
从集算器外部库的文件目录,安装目录 \esProc\extlib\MongoCli,获取所需的 jar 包。 外部库的核心 jar 包是 MongoCli.jar。bson-3.6.3.jar、mongo-java-driver-3.6.3.jar 是第三方 jar 包,请根据使用的 MongoDB 版本, 从网上下载并替换为正确 jar 包。
更多 MongoDB 计算示例,参考 辅助 MongoDB 计算
更多 SPL 应用,参考 SPL 应用计算
英文版