fhf*_*uih 4 javascript mongodb node.js bson
我有一个BSON来自mongoexport数据库的文件。我们假设数据库是todo,集合是items。现在我想将数据离线加载到我的 RN 应用程序中。由于集合可能包含任意多个文档(目前假设有 2 个),因此我想使用一种方法来解析文件,无论它包含多少个文档。
我尝试过以下方法:
bsondump可执行文件。JSON我们可以使用外部命令将文件转换为
bsondump --outFile items.json items.bson
Run Code Online (Sandbox Code Playgroud)
但我正在开发一个移动应用程序,因此在 shell 命令中调用第三方可执行文件并不理想。另外,输出包含多行单行 JSON 对象,因此从技术上讲,输出不是正确的 JSON 文件。所以事后解析并不优雅。
deserialize在js-bson图书馆使用根据js-bson文档,我们可以这样做
const bson = require('bson')
const fs = require('fs')
bson.deserialize(fs.readFileSync(PATH_HERE))
Run Code Online (Sandbox Code Playgroud)
但这会引发错误
Error: buffer length 173 must === bson size 94
Run Code Online (Sandbox Code Playgroud)
并通过添加此选项,
bson.deserialize(fs.readFileSync(PATH_HERE), {
allowObjectSmallerThanBufferSize: true
})
Run Code Online (Sandbox Code Playgroud)
错误已解决,但仅返回第一个文档。因为文档没有提到这个函数只能解析1个文档集合,所以我想知道是否有一些选项可以启用多个文档读取。
deserializeStreamjs-bsonlet docs = []
bson.deserializeStream(fs.readFileSync(PATH_HERE), 0, 2, docs, 0)
Run Code Online (Sandbox Code Playgroud)
但此方法需要文档计数参数(此处为 2)。
bson-stream库我实际上使用react-native-fetch-blob的是fs,并且根据他们的文档,流对象没有方法pipe,这是 doc 中演示的唯一方法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)
});
Run Code Online (Sandbox Code Playgroud)
另外我对上面的内容也不太确定ENCODING。
我阅读了源代码js-bson并找到了解决问题的方法。我觉得这里最好详细记录一下:
我们自己拆分文档,并将文档一一送入解析器。
假设.json我们的转储todo/items.bson是
{_id: "someid#1", content: "Launch a manned rocket to the sun"}
{_id: "someid#2", content: "Wash my underwear"}
Run Code Online (Sandbox Code Playgroud)
这显然违反了JSON 语法,因为没有外部对象将事物包装在一起。
编辑:我后来遇到了术语“JSON流”,它似乎描述了这种格式。该术语由(用于 JSON 操作的命令行工具)使用
jq,尽管该术语可能表明这些 JSON 文档旨在在流中逐一出现。
内部 BSON 具有类似的形状,但 BSON 似乎允许在一个文件中填充这种多对象。
那么对于每个文档,前四个字节表示这个文档的长度,包括这个前缀本身和后缀。后缀只是一个 0 字节。
最终的 BSON 文件类似于
LLLLDDDDDDD0LLLLDDD0LLLLDDDDDDDDDDDDDDDDDDDDDD0...
Run Code Online (Sandbox Code Playgroud)
其中L是长度,D是二进制数据,0字面意思是 0。
因此,我们可以开发一个简单的算法来获取文档长度,执行该算法bson.deserialize将从allowObjectSmallerThanBufferSize缓冲区开始获取第一个文档,然后切掉该文档并重复。
我提到的另一件事是在 React Native 上下文中进行编码。处理 React Native 持久性的库似乎都缺乏从文件读取原始缓冲区的支持。我们最接近的选择是,它是任何base64二进制文件的字符串表示形式。然后我们使用将字符串转换为缓冲区并输入到上面的算法中。Bufferbase64
反序列化.js
{_id: "someid#1", content: "Launch a manned rocket to the sun"}
{_id: "someid#2", content: "Wash my underwear"}
Run Code Online (Sandbox Code Playgroud)
应用程序.js
LLLLDDDDDDD0LLLLDDD0LLLLDDDDDDDDDDDDDDDDDDDDDD0...
Run Code Online (Sandbox Code Playgroud)
上述方法将文件作为一个整体读取。有时,当我们有一个非常大的.bson文件时,应用程序可能会崩溃。当然,可以更改readFile为readStream上面的内容并添加各种检查以确定当前块是否包含文档的结尾。这可能会很麻烦,而且我们实际上正在重写bson-stream库!
因此,我们可以创建一个RNFetchBlob文件流和另一个bson-stream解析流。这让我们回到了问题中的尝试#4 。
看完源码,BSON解析流继承自一个node.js Transform string。piping我们可以手动将块和事件转发到和onData,而不是。onEndon('data')on('end')
由于bson-stream不支持将选项传递给底层bson库调用,因此人们可能希望在自己的项目中稍微调整库源代码。
| 归档时间: |
|
| 查看次数: |
4883 次 |
| 最近记录: |