mongodb 多表关联update

mongodb需要连表操作的支持一直被大家诟病。当然在官方的宣称中使用mongodb如果需要连表的业务场景一般是没有真正用好mongodb的特性。把所有的东西都丢到一个集合里面不就好了么。

顺便在这里吐槽一下mongodb。mongodb刚刚流行的时候号称不支持事务等特性,让人觉得他们不可能成为一款数据库产品,mongodb的官方人员也号称他们起初也不是数据库。但自从mongodb 3.0版本以后,许多特性都加进来了。有种 把以前脱掉的衣服都一件件穿上的意思 ,好吧这个比喻有点别扭。不过mongodb的确会越来越重。好像有点扯远了。3.2版本中加入了lookup支持,大家可以参考看一下,请注意

$lookup will only be included in MongoDB Enterprise Server

此处最起码说明这个应该还不是很成熟。
好了不闲扯了。还说说一下mongodb中实现多表关联查询。语句不支持不要忘记JAVASCRITPT,关于js的应用已经在前面的一篇中说过了。
先讲一下业务场景:

我司的mongodb应用是用来存储流量访问日志。按照正常情况,流量数据应来自于核心交换上的流量抓包。在最初的数据库设计中,大神们分了三个表来存储流量数据 requet、response、rawdata 大家意会就好,具体的collecton起名类似。其中raw与request、response 通过某些id字段关联。在调试过程中引入了一部分垃圾数据,垃圾数据的原因是流量信息不全,无法定位访问人或者进行的具体业务操作。通过request的时间字段,可以方便的定位request中的垃圾数据。一时手快,便直接把这些remove掉了:

db.request.remove({foo:bar});  

但rawdata的剔除就有点懵逼了。按照往常写的话肯定是

delete from rawdata r where r.reqid not in (select id from request)

mongodb里面一时没有想到什么好办法。甚至想写个程序做逐条查询来搞定。但总感觉应该有简单易行的方式完成。最终写了一个用foreache的版本:

db.http_request.find().forEach(
        function(doc){
        var cur = db.http_rawdata.find({\"_id\":doc._id});
        if(cur.hasNext()){
            var raw= cur.next();
            raw.exits=\"1\";
            db.http_rawdata.save(raw);
        }  
        })

由于requst的collecton比rawdata要小很多(request中的垃圾数据已经剔除),此处选择了对request collecton做遍历。当然这样做的性能还是令人担忧的。不过比起存在这么多的垃圾数据占用磁盘,已经非常好了。当然更新完成后要做remove操作。exits属性只是临时做个标记,而且竟然还存在拼写错误,这种羞羞的事情是见不得人的。所以要删除这个属性:

db.http_rawdata.update(
{ exits: \"1\" },
{ $unset: { exits: \"\" } },false,true
)

最后想谈一下mongodb使用的业务场景,个人感觉如果存储非结构化的数据,比如日志,你会不定期的往里加点属性或者减点属性,选择mongodb是一件非常愉悦的事情。你不用在发布更新的时候添加一个烦人的,不是那么好追溯的sql文件让大家修改表结构。如果是结构化的数据,当然还是成熟的关系型数据库比较好。当然随之mongodb的版本演进,以后mongo也会越来越好用。

发表评论

电子邮件地址不会被公开。 必填项已用*标注