0

我有一个相当大的数据集合,由第三方制作,它包含一个 Bindata“包”列,其中实际存储了纯 ASCII。我的意思是,他们可以将文本存储为字符串。

我必须以 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。

我在任何地方都找不到解决方案,也许是因为没有人需要做像这样愚蠢的事情。

4

1 回答 1

8

JavaScript BinData 对象具有base64()hex()方法,您可以使用它们来接收相应格式的字符串。至于将这些值解码为 JS 中的文本字符串,您有一些选择:

根据BSON 规范,二进制数据字段由 32 位整数长度、子类型和字节数组组成。JS 中返回的 base64 和十六进制表示形式包含以整数长度为前缀的字节数组。这意味着在解码这些值之后,我们需要去掉前四个字节。这是使用这两个选项的示例:

// 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,我肯定会建议通过 shell 客户端而不是 执行脚本db.eval(),这样您就不会使用长时间运行的 JS 函数来锁定数据库。

于 2012-07-10T18:22:29.437 回答