眾所周知,mongodb是不支持join操作的,因此我們只能自己來實現這個功能。前段時間,我遇到這個一個業務場景:
collection A 的數據格式:
{ "_id" : { "username" : "jifeng.zjd", "version" : 2 }, "value" : 1 }
collection B 的數據格式:
{ "user_id" : 12630, "username" : "jifeng.zjd" }
A表的數據量為2w,B表的數據量為25w。為了說明簡單,我簡化下需求,就是計算A._id.username = B.username 的B表中的用戶數據,也就是求A和B的交集。沒有join,怎么辦呢?
相信大家都應該有自己的解答了,由於A表的數據量相對於B表來講是少的,所以可以先取出A表的所有數據,然后去B表查詢,看那些數據同時存在於A和B表中。當然在mongodb中對A和B建立適當的索引是非常必要的。我采用的方法是對B表的username字段進行索引。如對mongodb索引不了解,可以參見《mongoDB的索引使用及索引機制》 一文。
這里我使用的語言是nodejs,node_module采用的mongoskin,我剛開始寫了一個簡單的實現:
db.A.find({}, {}, function(err, adata){ if (err) return callback(err); //得到A表中的所有數據 adata.toArray(function(err, aArray){ if (err) return callback(err); var len = aArray.length; var result = []; for (var i = 0; i < len; i++) { var item = aArray[i]; var username = item._id.username; var op = {username: username}; //查看B表中這條數據 db.B.findOne(op, {}, function(err, data){ allcount++; if (data) { result.push(data.username); } if (allcount === len) { callback(null, result); } }) } }) })
這段代碼是能滿足業務需求,但大家有沒有發現它存在一個致命的問題?對,運行速度慢!
原因很簡單,我是從A表中批量取到所有數據,然后又用findOne方法一條條去B表中查詢,A表中有2w數據,也就是要查B表2w次,雖然B表中已經建立索引,但這樣的查詢邏輯明顯是不可接受。知道問題所在,解決方案也就清楚了:對B表進行批量查詢:
db.A.find({}, {}, function(err, adata){ if (err) return callback(err); //得到A表中的所有數據 adata.toArray(function(err, aArray){ if (err) return callback(err); var len = aArray.length; var result = []; var usernames = []; for (var i = 0; i < len; i++) { var item = aArray[i]; var username = item._id.username; usernames.push(username); } var op = {username: {$in: usernames}}; //查看B表中這條數據 db.B.find(op, {}, function(err, bdata){ ddata.toArray(function(err, barray){ callback(barray); }) }) }) })
經過這樣的優化,程序性能會有明顯的提升。
希望對大家有所幫助。