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 的查询?