Node.js 将mongoose流转换为数组
我曾与mongodb合作过,但对mongoose ORM来说是个新手。我试图从一个集合中获取数据,explain()输出显示为50ms。通过mongoose获取数据的总时间为9秒。以下是查询:Node.js 将mongoose流转换为数组,node.js,mongodb,stream,mongoose,Node.js,Mongodb,Stream,Mongoose,我曾与mongodb合作过,但对mongoose ORM来说是个新手。我试图从一个集合中获取数据,explain()输出显示为50ms。通过mongoose获取数据的总时间为9秒。以下是查询: Node.find({'dataset': datasetRef}, function (err, nodes){ // handle error and data here }); 然后我在我查询的字段上应用了索引。explain()输出现在显示为4ms。但通过mongoose检索数据的总时间没
Node.find({'dataset': datasetRef}, function (err, nodes){
// handle error and data here
});
然后我在我查询的字段上应用了索引。explain()输出现在显示为4ms。但通过mongoose检索数据的总时间没有改变。然后我搜索了一下,发现使用lean()有助于使mongoose中读取查询的性能非常接近本机mongodb
因此,我将查询更改为:
Node.find({'dataset': datasetRef})
.lean()
.stream({transform: JSON.stringify})
.pipe(res)
这完全解决了性能问题。但最终的结果是JSON文档流如下所示:
{var11: val11, var12: val12}{var21: val21, var22: val22} ...
我如何解析它以形成一个文档数组?或者我根本不应该使用流?在我看来,如果我计划在后端形成数组,那么使用流是没有意义的,因为我将不得不等待所有文档被读入内存。但我也认为,在前端解析和创建整个数组可能代价高昂
在这种情况下,如何在不阻塞网络的情况下实现最佳性能
更新
我正在尝试使用直通流解决这个问题。但是,我还不能在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);
有了这个,我可以得到开头的“[”和结尾的“]”。然而,仍然无法将patten“}{”替换为“},{”。不确定我做错了什么
更新2
现在明白了替换不起作用的原因了。由于我将转换函数指定为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);
我在这里面临的唯一问题是,我不知道它何时是流中的最后一个JSON对象
但是您知道哪一个是第一个。知道了这一点,您可以在每个对象(第一个对象除外)前面加逗号,而不必加逗号。为此,请在闭包中设置转换函数:
function transformFn(){
var first = true;
return function(data) {
if (first) {
first = false;
return JSON.stringify(data);
}
return "," + JSON.stringify(data);
}
}
现在,您可以调用该函数并将其设置为实际转换
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);
我喜欢@cdbajorin的解决方案,因此我创建了一个更具可读性的版本(ES6):
@cbajorin和@rckd都给出了正确的答案 然而,一直重复这段代码似乎很痛苦 因此,我的解决方案使用一个额外的转换流来实现同样的效果
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()
}
}
这反过来又可以用作:
const toArray = new ArrayTransform();
Model.find(query).lean().stream({transform: JSON.stringify })
.pipe(toArray)
.pipe(res)
编辑:添加了空检查是否尝试在第一个查询中传递精益选项?Node.find({'dataset':datasetRef}).lean().exec(函数(err,nodes){…});是的。问题是,文档之前作为单个数组存储在文档中,并存储在gridfs中。因此,在请求文档之前,响应在几毫秒内开始流式传输。现在,如果我要从该模型移动到该规范化模型,消除gridfs,我需要使用流式传输,否则响应会从后端延迟。这是什么原因如何使用直通流将模式(如
}{
)替换为},{
)呢?我正在尝试,但无法做到这一点
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/shoppingdb');
var Sports = mongoose.model('sports', {});
var result = [];
var prefix_out = "your info";
Sports.find({"goods_category": "parts"}).
cursor().
on("data", function(doc){
//stream ---> string
var str = JSON.stringify(doc)
//sring ---> JSON
var json = JSON.parse(str);
//handle Your Property
json.handleYourProperty = prefix_out + json.imageURL;
result.push(result);
}).
on('error', function(err){
console.log(err);
}).
on('close', function(){
console.log(result);
});
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/shoppingdb');
var Sports = mongoose.model('sports', {});
var result = [];
var prefix_out = "your info";
Sports.find({"goods_category": "parts"}).
cursor().
on("data", function(doc){
//stream ---> string
var str = JSON.stringify(doc)
//sring ---> JSON
var json = JSON.parse(str);
//handle Your Property
json.handleYourProperty = prefix_out + json.imageURL;
result.push(result);
}).
on('error', function(err){
console.log(err);
}).
on('close', function(){
console.log(result);
});