我已经使用node-oracledb几个月了,而且我已经成功实现了迄今为止我所需要的。
我目前正在开发一款搜索应用,可能会从一次通话中返回约2百万行数据。为了确保我不会断开与浏览器和服务器的连接,我想我会尝试使用queryStream,以便有一个持续的数据流回到客户端。
我按原样实现了queryStream示例,这适用于几十万行。但是,当返回的行大于一百万时,节点内存不足。通过记录和观察客户端和服务器日志事件,我可以看到客户端在发送和接收的行方面远远落后于服务器。因此,看起来Node正在倒下,因为它缓冲了如此多的数据。
值得注意的是,此时,我的selectstream实现位于通过Express调用的req / res函数内。
要返回数据,我会做类似......
stream.on('data', function (data) {
rowcount++;
let obj = new myObjectConstructor(data);
res.write(JSON.stringify(obj.getJson());
});
我一直在阅读关于流和管道如何帮助流程的知识,所以我希望能够做的是能够将查询的结果传递给a)帮助流程b)在发送回客户端之前能够将结果传递给其他函数。
E.g。
function getData(req, res){
var stream = myQueryStream(connection, query);
stream
.pipe(toSomeOtherFunction)
.pipe(yetAnotherFunction)
.pipe(res);
}
我花了几个小时试图找到一个允许我输出结果的解决方案或示例,但我陷入困境并需要一些帮助。
道歉,如果我错过了一些明显的东西,但我仍然要掌握Node,尤其是溪流。
提前致谢。
答案 0 :(得分:1)
这里有一点阻抗不匹配。 queryStream API会发出JavaScript对象的行,但是要传递给客户端的是JSON数组。你基本上必须在开头添加一个开括号,在每行后添加一个逗号,并在末尾添加一个括号。
我将告诉您如何在直接使用驱动程序的控制器中执行此操作,而不是像我在this series中提倡的那样使用单独的数据库模块。
const oracledb = require('oracledb');
async function get(req, res, next) {
try {
const conn = await oracledb.getConnection();
const stream = await conn.queryStream('select * from employees', [], {outFormat: oracledb.OBJECT});
res.writeHead(200, {'Content-Type': 'application/json'});
res.write('[');
stream.on('data', (row) => {
res.write(JSON.stringify(row));
res.write(',');
});
stream.on('end', () => {
res.end(']');
});
stream.on('close', async () => {
try {
await conn.close();
} catch (err) {
console.log(err);
}
});
stream.on('error', async (err) => {
next(err);
try {
await conn.close();
} catch (err) {
console.log(err);
}
});
} catch (err) {
next(err);
}
}
module.exports.get = get;
获得概念之后,您可以使用可重用的Transform类简化一些事情,它允许您在控制器逻辑中使用管道:
const oracledb = require('oracledb');
const { Transform } = require('stream');
class ToJSONArray extends Transform {
constructor() {
super({objectMode: true});
this.push('[');
}
_transform (row, encoding, callback) {
if (this._prevRow) {
this.push(JSON.stringify(this._prevRow));
this.push(',');
}
this._prevRow = row;
callback(null);
}
_flush (done) {
if (this._prevRow) {
this.push(JSON.stringify(this._prevRow));
}
this.push(']');
delete this._prevRow;
done();
}
}
async function get(req, res, next) {
try {
const toJSONArray = new ToJSONArray();
const conn = await oracledb.getConnection();
const stream = await conn.queryStream('select * from employees', [], {outFormat: oracledb.OBJECT});
res.writeHead(200, {'Content-Type': 'application/json'});
stream.pipe(toJSONArray).pipe(res);
stream.on('close', async () => {
try {
await conn.close();
} catch (err) {
console.log(err);
}
});
stream.on('error', async (err) => {
next(err);
try {
await conn.close();
} catch (err) {
console.log(err);
}
});
} catch (err) {
next(err);
}
}
module.exports.get = get;