眾所周知,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);
})
})
})
})
經過這樣的優化,程序性能會有明顯的提升。
希望對大家有所幫助。
