MongoDB 记录的字段不同时如何合并求和

MongoDB数据库采用bson的格式存储存储的内容是文档型的每一条记录就是一个文档,每个文档中的键不一定相同,键的个数也不一定相等,对这样嵌套的文档结构关系,进行分组统计就比较麻烦。比如有以下数据集
{"name": "test","num": {"text": 1,"face": 2}},
{"name": "test","num": {"image": 3,"face": 4}},
{"name": "test","num": {"text":5,"image": 6, "book": 12}},
{"name": "demo","num": {"text": 3,"face": 4}},
{"name": "demo","num": {"image": 7,"face": 8}},
{"name": "demo","num": {"text":5,"image": 5}}
 
希望获得各产品数量,查询结果为:
{"_id" : "test",  "count" : { "image" : 9, "book" : 12, "face" : 6, "text" : 6} }
{"_id" : "demo", "count" : { "image" : 12, "text" : 8, "face" : 12} }

用 MongoDB 脚本实现思路,先将 num 作为数组拆开,转换成文档分别统计,完成后重新分组过滤显示,实现比较复杂。

使用集算器,将数据整理成序表,通过序表分组求和, 再行列转换就可以,这样就方便得多了。
集算器安装包可去润乾网站下载,运行时需要一个授权,免费版本就够用。

我们将上面描述实现步骤:
1.    在集算器中编写脚本 test.dfx:

A B
1 =mongo_open("mongodb://localhost:27017/cookie  ") / 连接数据库
2 =mongo_shell(A1,"test.find( {},   {_id: 0})").fetch() / 查询集合 test
3 =A2.(~.(( d=num.array(),   num.fname().( name|~| d(#)) )).conj()) / 将 num 下的字段与其及对应
4 =create(NAME, SNAME,   NUM).record(A3.conj()) /A3 记录存储新序表
5 =A4.groups(NAME, SNAME; sum(NUM):   COUNT) / 按 NAME,SNAME 分组对 num 求和
6 =A5.pivot(NAME;SNAME,COUNT) / 进行行列转换, 将 SNAME,COUNT 行变成列
7 >mongo_close(A1) / 关闭连接

2.    调试执行一下,可以看到 A3 的格值为
A3 Member

[test,text,1.0,…]
[test,image,3.0,…]

> 其它格值就不再一一列出。
3.    执行脚本返回结果:
A6 NAME book face image

demo (null) 12.0 12.0
test 12.0 6.0 9.0

A3中把 NUM 下的列名与其值对应,再与 NAME 组成一条条记录, A4 将记录存入序表;对序表分组求和再进行行列转换。

集算器提供了 JDBC 接口,上述脚本 test.dfx 很容易集成到 Java 中:

public
static void doTest() {
    Connection con = null;
    java.sql.Statement st;
   
    try{
        Class.forName("com.esproc.jdbc.InternalDriver");
        con = DriverManager.getConnection("jdbc:esproc:local://"); 
// 调用 test.dfx 脚本
        st=con.createStatement(); 
ResultSet rst = st.executeQuery("call test");
        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脚本》。