如何使用JavaScript中任意多个文档反序列化转储的BSON?

如何使用JavaScript中任意多个文档反序列化转储的BSON?,javascript,node.js,mongodb,bson,Javascript,Node.js,Mongodb,Bson,我有一个BSON文件,它来自数据库的mongoexport。假设数据库是todo,集合是items。现在我想将数据脱机加载到我的RN应用程序中。由于集合可能包含任意多个文档(假设当前有2个),因此我想使用一种方法来解析文件,不管它包含多少文档 我尝试过以下方法: 使用外部bsondump可执行文件 我们可以使用外部命令将文件转换为JSON bsondump --outFile items.json items.bson 但我正在开发一个移动应用程序,所以在shell命令中调用第三方可执行文件并

我有一个
BSON
文件,它来自数据库的
mongoexport
。假设数据库是
todo
,集合是
items
。现在我想将数据脱机加载到我的RN应用程序中。由于集合可能包含任意多个文档(假设当前有2个),因此我想使用一种方法来解析文件,不管它包含多少文档

我尝试过以下方法:

  • 使用外部
    bsondump
    可执行文件
  • 我们可以使用外部命令将文件转换为
    JSON

    bsondump --outFile items.json items.bson
    
    但我正在开发一个移动应用程序,所以在shell命令中调用第三方可执行文件并不理想。另外,输出包含几行一行JSON对象,因此从技术上讲,输出不是正确的JSON文件。因此,事后解析并不优雅

  • js bson
    库中使用
    反序列化
  • 根据法律规定,我们可以这样做

    const bson = require('bson')
    const fs = require('fs')
    bson.deserialize(fs.readFileSync(PATH_HERE))
    
    但这带来了一个错误

    Error: buffer length 173 must === bson size 94
    
    加上这个选项,

    bson.deserialize(fs.readFileSync(PATH_HERE), {
        allowObjectSmallerThanBufferSize: true
    })
    
    错误已解决,但只返回第一个文档。因为文档中没有提到这个函数只能解析1-document集合,所以我想知道是否有一些选项支持多文档读取

  • js bson
  • 但此方法需要一个文档计数参数(此处为2)

  • 使用
    bson-stream
  • 实际上,我使用的是
    react native fetch blob
    而不是
    fs
    ,根据他们的文档,stream对象没有
    pipe
    方法,这是在
    bson stream
    doc中演示的唯一方法。因此,尽管这种方法不需要文档数量,但我不知道如何使用它

    // fs
    const BSONStream = require('bson-stream');
    fs.createReadStream(PATH_HERE).pipe(new BSONStream()).on('data', callback);
    
    // RNFetchBlob
    const RNFetchBlob = require('react-native-fetch-blob');
    RNFetchBlob.fs.readStream(PATH_HERE, ENCODING)
    .then(stream => {
        stream.open();
        stream.can_we_pipe_here(new BSONStream())
        stream.onData(callback)
    });
    

    另外,我不确定上面的
    编码。

    我已经阅读了
    js bson
    的源代码,并找到了解决问题的方法。我认为最好在这里保存详细记录:

    方法1 我们自己分割文档,并将文档逐个提供给解析器

    BSON内部格式 假设我们的
    todo/items.bson
    .json
    转储是

    {_id: "someid#1", content: "Launch a manned rocket to the sun"}
    {_id: "someid#2", content: "Wash my underwear"}
    
    这显然违反了JSON语法,因为没有外部对象将事物包装在一起

    内部BSON的形状类似,但似乎BSON允许在一个文件中填充这种多对象

    然后,对于每个文档,四个前导字节表示该文档的长度,包括前缀本身和后缀。后缀只是一个0字节

    最终的BSON文件类似于

    LLLLDDDDDDD0LLLLDDD0LLLLDDDDDDDDDDDDDDDDDDDDDD0...
    
    其中,
    L
    是长度,
    D
    是二进制数据,
    0
    实际上是0

    算法 因此,我们可以开发一个简单的算法来获取文档长度,使用
    allowObjectsSmallerThanBufferSize
    进行
    bson.反序列化
    ,这将从缓冲区开始获取第一个文档,然后切掉该文档并重复

    关于编码 我提到的另一件事是在React本地上下文中进行编码。处理React Native persistent的库似乎都缺乏从文件读取原始缓冲区的支持。我们最接近的选择是
    base64
    ,它是任何二进制文件的字符串表示形式。然后我们使用
    Buffer
    base64
    字符串转换为缓冲区,并输入上述算法

    代码 反序列化.js

    const BSON=require('BSON');
    函数_getNextObjectSize(缓冲区){
    //这就是BSON的方式
    返回缓冲区[0]|(缓冲区[1]反序列化(缓冲区数据))
    .then(jsData=>{/*在此处执行任何操作*/})
    
    方法2 上面的方法读取整个文件。有时,当我们有一个非常大的
    .bson
    文件时,应用程序可能会崩溃。当然,可以将上面的
    readFile
    更改为
    readStream
    ,并添加各种检查以确定当前区块是否包含文档的结尾。这可能会很麻烦,而且我们实际上是r通过电子方式编写
    bson-stream

    因此,我们可以创建一个
    RNFetchBlob
    文件流,以及另一个
    bson流
    解析流。这让我们回到了问题中的尝试4

    阅读源代码后,BSON解析流从node.js转换字符串继承而来。我们可以手动将
    onData
    onEnd
    中的块和事件转发到
    on('data')
    on('end')

    由于
    bson-stream
    不支持将选项传递给底层
    bson
    库调用
    ,因此可能需要在自己的项目中稍微调整库源代码

    LLLLDDDDDDD0LLLLDDD0LLLLDDDDDDDDDDDDDDDDDDDDDD0...