2012-07-10 62 views
0

我有一個相當大的第三方數據集合,它包含一個實際存儲純ASCII的Bindata「包」列。 我的意思是,他們可以將文本存儲爲字符串。在mongodb中導出保存爲Bindata的文本

我必須以csv格式導出這個集合,這對於mongoexport來說效果很好,但是輸出包含「包」列的base64編碼值。我需要該欄中的實際文字,而不是BinData(0,\"NDYuN.....==")

什麼我試過到目前爲止是一個新列「RAWDATA」,類似這樣的更新集合:

db.segments.find({"_id" : ObjectId("4fc79525f65181293930070b")}).forEach(function(data) { 
    db.segments.update(
    {_id:data._id}, 
    {$set:{ "rawData" : data.package.toString() }} 
); 
}); 

我已經限制查找到只有一個文件,直到我得到它的權利。 不幸的是toString並沒有達到我期望的魔法。

而且,我已經試過這樣:

db.segments.find({"_id" : ObjectId("4fc79525f65181293930070b")}).forEach(function(data){ 
    data.package = new String(data.package); 
    db.segments.save(data); 
}); 

結果更慘。

如果我使用php讀取文檔,$response = $db->execute('return db.segments.findOne()');然後print_r($response),我可以驗證數據是否正確存儲爲base64。

我無法在任何地方找到解決方案,也許是因爲沒有人需要像這樣做一些愚蠢的事情。

回答

8

JavaScript BinData對象有base64()hex()方法,您可以使用這些方法接收相應格式的字符串。至於這些值解碼成內JS文本字符串,你有一些選項:

按照BSON spec,二進制數據字段由32位的整數長度的,子類型和字節數組。 JS中返回的base64和十六進制表示包含前綴爲整數長度的字節數組。這意味着在對這些值進行解碼之後,我們需要去掉前四個字節。下面是使用這兩個選項的例子:

// https://stackoverflow.com/a/3058974/162228 
function decode_base64(s) { 
    var e={},i,k,v=[],r='',w=String.fromCharCode; 
    var n=[[65,91],[97,123],[48,58],[43,44],[47,48]]; 

    for(z in n){for(i=n[z][0];i<n[z][1];i++){v.push(w(i));}} 
    for(i=0;i<64;i++){e[v[i]]=i;} 

    for(i=0;i<s.length;i+=72){ 
     var b=0,c,x,l=0,o=s.substring(i,i+72); 
     for(x=0;x<o.length;x++){ 
      c=e[o.charAt(x)];b=(b<<6)+c;l+=6; 
      while(l>=8){r+=w((b>>>(l-=8))%256);} 
     } 
    } 
    return r; 
} 

// https://stackoverflow.com/a/3745677/162228 
function hex2a(hex) { 
    var str = ''; 
    for (var i = 0; i < hex.length; i += 2) 
     str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); 
    return str; 
} 

db.segments.find().forEach(function(doc){ 
    print(decode_base64(doc.package.base64())); 
}); 

db.segments.find().forEach(function(doc){ 
    print(hex2a(doc.package.hex())); 
}); 

這裏是一個小PHP腳本,我用來插入一些固定的數據:

<?php 

$mongo = new Mongo(); 
$c = $mongo->selectCollection('test', 'segments'); 
$c->drop(); 

$c->save(['package' => new MongoBinData('foo')]); 
$c->save(['package' => new MongoBinData('bar')]); 

foreach ($c->find() as $doc) { 
    printf("%s\n", $doc['bindata']->bin); 
} 

根據數據集的大小,可能更合理地做PHP中的二進制字段轉換。如果你想使用JavaScript,我肯定會建議通過shell客戶端而不是db.eval()來執行腳本,所以你不要使用長時間運行的JS函數來鎖定數據庫。

+0

謝謝,這是一個非常好的答案!我選擇了PHP的方式,但其他功能也很好。唯一的問題是,我不得不從用法示例中刪除'.substr(4)',因爲我的數據被「裁剪」(結果以72247而不是46.772247開頭)。 – ceteras 2012-07-11 08:20:31

+0

有趣。介意我問你使用的MongoDB的版本是什麼?上面有2.1.0運行。如果我插入二進制數據「foo」,然後在JS控制檯中選擇它,它的'hex()'方法返回'03000000666f6f'。 – jmikola 2012-07-11 15:33:41

+0

我正在使用1.8.2 – ceteras 2012-08-01 14:43:12