有没 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支持MongoDBjson查询表达式(findcountdistinctaggregate),比如区间查询写作:=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 脚本