我有一个来自数据库BSON
的{{1}}文件。假设数据库为mongoexport
,集合为todo
。现在,我想将数据脱机加载到RN应用程序中。由于该集合可能包含任意多个文档(当前说2个),因此我想使用一种方法来解析该文件,无论它包含多少文档。
我尝试了以下方法:
items
可执行文件。我们可以使用外部命令将文件转换为bsondump
JSON
但是我正在开发移动应用程序,因此在shell命令中调用第三方可执行文件不是理想的选择。另外,输出包含几行一线JSON对象,因此从技术上讲输出不是是正确的JSON文件。因此,事后解析并不优雅。
bsondump --outFile items.json items.bson
库中使用deserialize
根据js-bson
documentation,我们可以做到
js-bson
但这会引发错误
const bson = require('bson')
const fs = require('fs')
bson.deserialize(fs.readFileSync(PATH_HERE))
并添加此选项,
Error: buffer length 173 must === bson size 94
错误已解决,但仅返回第一个文档。因为文档中没有提到此功能只能解析1-document集合,所以我想知道是否有某些选项可以读取多个文档。
bson.deserialize(fs.readFileSync(PATH_HERE), {
allowObjectSmallerThanBufferSize: true
})
中使用deserializeStream
js-bson
但是此方法需要一个文档计数参数(此处为2)。
let docs = []
bson.deserializeStream(fs.readFileSync(PATH_HERE), 0, 2, docs, 0)
库我实际上是在使用bson-stream
而不是react-native-fetch-blob
,并且根据他们的文档,流对象没有fs
方法,这是演示的唯一方法在pipe
文档中。因此,尽管此方法不需要大量文档,但是我却对如何使用感到困惑。
bson-stream
我也不确定上面的// 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)
});
。
答案 0 :(得分:0)
我已经阅读了js-bson
的源代码,并找到了解决该问题的方法。我认为最好在这里保留详细的记录:
假设我们的.json
的{{1}}转储为
todo/items.bson
明显破坏 JSON语法。内部BSON具有相似的形状,但似乎BSON 允许将这种多对象填充到一个文件中。
然后对于每个文档,前四个字节指示该文档的长度,包括此前缀本身和后缀。后缀只是一个0字节。
最终的BSON文件类似于
{_id: "someid#1", content: "Launch a manned rocket to the sun"}
{_id: "someid#2", content: "Wash my underwear"}
其中LLLLDDDDDDD0LLLLDDD0LLLLDDDDDDDDDDDDDDDDDDDDDD0...
是长度,L
是二进制数据,D
实际上是0。
因此,我们可以开发一种简单的算法来获取文档长度,将0
与bson.deserialize
进行比较,这将从缓冲区开始处获取第一个文档,然后将该文档切成薄片并重复。
我提到的另一件事是在React Native上下文中进行编码。处理React Native持久性的库似乎都缺乏从文件读取原始缓冲区的支持。我们最接近的选择是allowObjectSmallerThanBufferSize
,它是 any 二进制文件的字符串表示形式。然后,我们使用base64
将Buffer
字符串转换为缓冲区并馈入上述算法。
deserialize.js
base64
App.js
const BSON = require('bson');
function _getNextObjectSize(buffer) {
// this is how BSON
return buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
}
function deserialize(buffer, options) {
let _buffer = buffer;
let _result = [];
while (_buffer.length > 0) {
let nextSize = _getNextObjectSize(_buffer);
if (_buffer.length < nextSize) {
throw new Error("Corrupted BSON file: the last object is incomplete.");
}
else if (_buffer[nextSize - 1] !== 0) {
throw new Error(`Corrupted BSON file: the ${_result.length + 1}-th object does not end with 0.`);
}
let obj = BSON.deserialize(_buffer, {
...options,
allowObjectSmallerThanBufferSize: true,
promoteBuffers: true // Since BSON support raw buffer as data type, this config allows
// these buffers as is, which is valid in JS object but not in JSON
});
_result.push(obj);
_buffer = _buffer.slice(nextSize);
}
return _result;
}
module.exports = deserialize;