0

サードパーティによって作成された非常に大きなデータのコレクションがあります。これには、プレーンASCIIが実際に保存されているBindata「パッケージ」列が含まれています。つまり、テキストを文字列として保存できたはずです。

このコレクションを mongoexport で非常にうまく機能する csv 形式でエクスポートする必要がありますが、出力には「パッケージ」列の 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() }}
  );
});

うまくいくまで、検索を 1 つのドキュメントに限定しました。残念ながら、 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 として適切に保存されていることを検証できます。

おそらく、誰もこれほど愚かなことをする必要がなかったからでしょう。

4

1 に答える 1

8

JavaScriptのBinDataオブジェクトにはメソッドbase64()hex()メソッドがあり、それぞれの形式で文字列を受け取るために使用できます。これらの値をJS内でテキスト文字列にデコードする場合、いくつかのオプションがあります。

BSON仕様によると、バイナリデータフィールドは32ビット整数長、サブタイプ、およびバイト配列で構成されます。JSで返されるbase64および16進表現には、整数の長さが前に付いたバイト配列が含まれています。つまり、値をデコードした後、最初の4バイトを削除する必要があります。両方のオプションを使用した例を次に示します。

// https://stackoverflow.com/a/3058974/162228
function decode_base64(s) {
    var e={},i,k,v=[],r='',w=String.fromCharCode,u=0;
    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;}
    function a(c){
      if(c<128)r+=w(c);else if(c>=192)u=c;else r+=w(((u&31)<<6)+(c&63));
    }

    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)a((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を利用したい場合は、スクリプトをではなくシェルクライアント経由で実行することを強くお勧めしdb.eval()ます。そうすれば、長時間実行されるJS関数でデータベースをロックすることはありません。

于 2012-07-10T18:22:29.437 に答える