将猫鼬流转换为数组

Man*_*ngh 5 stream mongoose mongodb node.js

我曾与mongodb合作,但对mongoose ORM还是很​​陌生。我试图从集合中获取数据,explain()输出显示50ms。通过猫鼬获取数据的总时间为9秒。这是查询:

Node.find({'dataset': datasetRef}, function (err, nodes){
   // handle error and data here
});
Run Code Online (Sandbox Code Playgroud)

然后,我在要查询的字段上应用了索引。现在explain()输出显示为4ms。但是通过猫鼬检索数据的总时间没有改变。然后我搜索了一下,发现使用lean()可以帮助使mongoose中的读取查询性能与本地mongodb非常接近

所以我将查询更改为:

Node.find({'dataset': datasetRef})
.lean()
.stream({transform: JSON.stringify})
.pipe(res)
Run Code Online (Sandbox Code Playgroud)

这样就完全解决了性能问题。但是最终结果是像这样的JSON文档流:

{var11: val11, var12: val12}{var21: val21, var22: val22} ...
Run Code Online (Sandbox Code Playgroud)

我如何解析它形成文档数组?还是我根本不应该使用流?我认为,如果我打算在后端形成数组,则没有必要使用流,因为那样我将不得不等待所有文档都读入内存。但我也认为,在前端解析和创建整个数组可能会很昂贵。

在这种情况下,如何在不堵塞网络的情况下获得最佳性能?

更新

我正在尝试使用直通流解决此问题。但是,我还不能在JSON对象之间插入逗号。请参见下面的代码:

res.write("[");

var through = require('through');
var tr = through(
  function write(data){
    this.queue(data.replace(/\}\{/g,"},{"));
  }
);

var dbStream = db.node.find({'dataset': dataSetRef})
.lean()
.stream({'transform': JSON.stringify});

dbStream.on("end", function(){
    res.write("]");
});

dbStream
.pipe(tr)
.pipe(res);
Run Code Online (Sandbox Code Playgroud)

这样,我就可以在开头获得“ [”,在结尾获得“]”。但是,仍然无法将样式“} {”替换为“},{”。不知道我在做什么错

更新2

现在找出为什么替换无法正常工作。看来,由于我已将transform函数指定为JSON.stringify,因此它一次只能读取一个JSON对象,因此永远不会遇到该模式,}{因为它一次不会选择多个JSON元素。

现在,我修改了代码,并编写了一个自定义转换函数,该函数执行JSON.stringify,然后在末尾添加逗号。我在这里面临的唯一问题是我不知道它何时是流中的最后一个JSON对象。因为我不想在这种情况下附加逗号。目前,遇到结尾时,我会添加一个空的JSON对象。但是,这看起来并不令人信服。这是代码:

res.write("[");
function transform(data){
    return JSON.stringify(data) + ",";
}

var dbStream = db.node.find({'dataset': dataSetRef})
.lean()
.stream({'transform': transform});

dbStream.on("end", function(){
    res.write("{}]");
});

dbStream
.pipe(res);
Run Code Online (Sandbox Code Playgroud)

cdb*_*rin 6

我在这里面临的唯一问题是我不知道它何时是流中的最后一个JSON对象。

但是您确实知道哪个是第一个。知道了,您可以将其添加到除第一个对象之外的所有对象之前,而不是附加逗号。为此,请在闭包内设置您的转换函数:

function transformFn(){

    var first = true;

    return function(data) {

        if (first) {

            first = false;
            return JSON.stringify(data);
        }
        return "," + JSON.stringify(data);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您只需调用该函数并将其设置为实际转换即可。

var transform = transformFn();
res.write("[");
var dbStream = db.node.find({'dataset': dataSetRef})
.lean()
.stream({'transform': transform});

dbStream.on("end", function(){
    res.write("]");
});

dbStream
.pipe(res);
Run Code Online (Sandbox Code Playgroud)


pix*_*eet 5

@cbajorin和@rckd都给出了正确的答案。

但是,一直重复这段代码似乎很痛苦。

因此,我的解决方案使用了额外的Transform流来实现相同的目的。

    import { Transform } from 'stream'

class ArrayTransform extends Transform {
    constructor(options) {
        super(options)
        this._index = 0
    }

    _transform(data, encoding, done) {
        if (!(this._index++)) {
            // first element, add opening bracket
            this.push('[')
        } else {
            // following element, prepend comma
            this.push(',')
        }
        this.push(data)
        done()
    }

    _flush(done) {
        if (!(this._index++)) {
            // empty
            this.push('[]')
        } else {
            // append closing bracket
            this.push(']')
        }
        done()
    }
}
Run Code Online (Sandbox Code Playgroud)

依次可以用作:

const toArray = new ArrayTransform();
Model.find(query).lean().stream({transform: JSON.stringify })
    .pipe(toArray)
    .pipe(res)
Run Code Online (Sandbox Code Playgroud)

编辑:添加检查为空