MongoDB 的表上怎么做 JOIN?

 

SQL 和 NoSQL 数据库之间最大的区别之一是 JOIN。虽然 MongoDB 推出 $lookup 作为 NoSQL 数据库中使用关系数据时的一种补充,但即使是很简单的两表关联,用 $lookup 也需要替换成复杂的聚合查询,实际应用环境错综复杂,当遇到数据多层嵌套和多表关联,$lookup 很难解决。其实如果使用Open-esProc,先通过 MongoDB 简单查询,再结合 SPL 语法(类 SQL 的计算),不仅能完成 SQL 的全部功能,而且特别擅长处理多层数据。举个例子,两关联表数据如下。

History:

_id id History child_id
1 001 today worked ch001
2 002 Working ch004
3 003 now working ch009

childsgroup:

_id gid name childs
1 g001 group1 {"id":"ch001","info":{"name":"a",mobile:1111}},{"id":"ch002","info":{"name":"b",mobile:2222}}
2 g002 group1 {"id":"ch004","info":{"name":"c",mobile:3333}},{"id":"ch009","info":{"name":"d",mobile:4444}}
 

History中的child_id与表childsgroup中的childs.id关联,希望得到下面结果:

{
    "_id" : ObjectId("5bab2ae8ab2f1bdb4f434bc3"),
    "id" : "001",
    "history" : "today worked",
    "child_id" : "ch001",
    "childInfo" :
    {
         "name" : "a",
        " mobile" : 1111
    }
   ………………
}

用 MongoDB 查询实现如下:

db.history.aggregate([
    {$lookup: {
        from:   "childsgroup",
        let: {child_id:   "$child_id"},
       pipeline: [
            {$match: {   $expr: { $in: [ "$$child_id", "$childs.id"] } } },
            {$unwind:   "$childs"},
            {$match: {   $expr: { $eq: [ "$childs.id", "$$child_id"] } } },
            {$replaceRoot: {   newRoot: "$childs.info"} }
            ],
            as:   "childInfo"
        }},
  {"$unwind": "$childInfo"}
])

这个脚本用了几个函数 lookup、pipeline、match、unwind、replaceRoot 处理,一般 mongoDB 用户不容易写出这样复杂脚本,如果用 SPL 脚本实现:

A B
1 =mongo_open("mongodb://127.0.0.1:27017/raqdb")
2 =mongo_shell(A1,"history.find()").fetch()
3 =mongo_shell(A1,"childsgroup.find()").fetch()
4 =A3.conj(childs)
5 =A2.join(child_id,A4:id,info)
6 >A1.close()

关联查询结果:

_id id history child_id info
1 001 today worked ch001 [a,1111]
2 002 working ch004 [c,3333]
3 003 now working ch009 [d,4444]

脚本说明:
       A1:连接 mongodb 数据库。
       A2:获取 history 表中的数据。
       A3:获取 childsgroup 表中的数据。
       A4:将 childsgroup 中的 childs 数据提取出来合并成序表。
       A5:表 history 中的 child_id 与表 childs 中的 id 关联查询,追加 info 字段, 返回序表。
       A6:关闭数据库连接。

相对 mongoDB 脚本写法,SPL 脚本的难度降低了不少,思路也更加清晰,也不需要再去熟悉有关 mongo 函数的用法,以及如何去组合处理数据等,节约了不少时间。

MongoDB 提供 $lookup 对多表关联实现了基本支持,但面对一些比较复杂的关联情况,往往查询脚本过于复杂,而如果使用 Open-esProc 的 SPL 脚本,利用其强大的语法、良好的易用性恰好能弥补 MongoDB 这方面的不足。若想了解更多关联计算示例,可参考 简化 MongoDB 关联运算
 
SPL 脚本对 MongoDB 数据进行了关联计算后,其结果还可以被 java 应用程序很容易地使用。SPL 有专门的 JDBC 驱动程序,通过 JDBC 调用 SPL 脚本,返回结果集,详情参考 用 Java 如何对 MongoDB 执行类似 SQL 的查询?