MongoDB 如何通过数组字段进行关联查找

从关联表记录数组中查找符合条件的数据, 用给定的字段组合成新表。
如有两集合 users, workouts,数组字段 users.WorkId 与 workouts._id 有关联。

users _id Name WorkId
1000 xxx [2,4,6]
1002 yyy [1,3,5]
workouts _id Date Book
1 1/1/2001 Othello
2 2/2/2001 A   Midsummer Night's Dream
3 3/3/2001 The Old   Man and the Sea
4 4/4/2001 GULLIVER'S   TRAVELS
5 5/5/2001 Pickwick   Papers
6 6/6/2001 The Red   and the Black
7 7/7/2001 Running
  期望查询结果:
Name _id Date Book
xxx 2 2/2/2001 A   Midsummer Night's Dream
xxx 4 4/4/2001 GULLIVER’S   TRAVELS
xxx 6 6/6/2001 The Red   and the Black
yyy 1 1/1/2001 Othello
yyy 3 3/3/2001 The Old   Man and the Sea
yyy 5 5/5/2001 Pickwick   Papers

用 MongoDB 脚本实现思路,可用 $lookup 函数将 users,workouts 两个集合关联查询,用 unwind 拆解 users. workouts成记录,并将它们提升到预层 (与 NAME 同层),再显示需要的列,实现过程比较烦琐。

使用集算器, 只要将 workouts._id 存在 users.WorkId 中的记录的 name 追加到 workouts 集合即可,实现比较容易。

集算器安装包可去润乾网站下载,运行时需要一个授权,免费版本就够用。
我们将上述描述事例实现步骤:

1.    在集算器中编写脚本workout.dfx

A B
1 =mongo_open("mongodb://127.0.0.1:27017/raqdb") / 连接 MongDB 数据库
2 =mongo_shell(A1,"users.find()").fetch() / 获取集合 users 数据
3 =mongo_shell(A1,"workouts.find()").fetch() / 获取集合 workouts 数据
4 =A2.conj(A3.select(A2.WorkId.pos(_id)).derive(A2.name:Name)) / 查询序表 A3 的 _id 值存在于序表 A2 中 WorkId 数组的记录, 并追加 name 字段,返回合并的序表。
5 >mongo_close(A1) / 关闭连接

2.      执行脚本返回结果

_id Date Book Name
2 2/2/2001 A   Midsummer Night's Dream xxx
4 4/4/2001 GULLIVER’S   TRAVELS xxx
6 6/6/2001 The Red   and the Black xxx
1 1/1/2001 Othello yyy
3 3/3/2001 The Old   Man and the Sea yyy
5 5/5/2001 Pickwick   Papers yyy
A4:A3.select() 就是 workouts 查询 _id 存在 users.WorkId 中的记录,把结果集的 name 追加到 workouts。

集算器提供了 JDBC 接口,脚本 workout.dfx 很容易集成到 Java 中:
public
static void doWorkout() {
    Connection con = null;
    java.sql.Statement st;
   
    try{
        Class.forName("com.esproc.jdbc.InternalDriver");
        con = DriverManager.getConnection("jdbc:esproc:local://"); 
st=con.createStatement(); 
// 调用脚本 workout.dfx
ResultSet rst = st.executeQuery("call workout");
        System.out.println(rst);
    }catch(Exception e){
        System.out.println(e);
    }finally{
        // 关闭连接
        if (con!=null) {
            try {
                con.close();
            }catch(Exception e) {
                System.out.println(e);
            }
        }  
    }
}

集算器与 JAVA 集成的进一步信息可参考:《Java 如何调用 SPL 脚本》。