【问题标题】:node.js stream array of json to responsejson的node.js流数组以响应
【发布时间】:2015-04-30 12:12:57
【问题描述】:

我有一个 REST 方法,它应该返回一个 JSON 数组,其中包含从 mongodb 读取的某些元素(使用 mongoose)。

应该很简单(实际情况下 find 方法有参数,但这不是问题):

OutDataModel.find().stream({transform: JSON.stringify}).pipe(res);

这种方法的问题是我没有得到有效的 JSON,因为结果是这样的:

{"id":"1","score":11}{"id":"2","score":12}{"id":"3","score":13}

我期待这个:

[{"id":"1","score":11},{"id":"2","score":12},{"id":"3","score":13}]

我还没有找到解决方案,但我很确定会有一个简单的解决方案。

我的尝试:

没有什么让我感到自豪的,但它就是这样。

  1. 在流​​式传输之前将 '[' 写入响应。
  2. 我提供了另一种调用 JSON.stringify 并在末尾添加 ',' 的方法,而不是 JSON.stringify
  3. 在流​​的“结束”事件中,我将']' 写入响应。

仍然无法使用此“解决方案”,因为我在末尾有一个逗号,如下所示:

 [{"id":"1","score":11},{"id":"2","score":12},{"id":"3","score":13},]

正如我所说,我很确定应该有一个干净的解决方案,因为它应该很常见。

这个方法会有很多并发调用,所以我不想把所有的东西都读入内存,然后再把所有的东西都写到响应中。每次调用都不会返回很多记录,但它们加在一起可能会很大。消费者是一个带有spring的java应用,使用jackson解析JSON。

请告诉我怎么做。

回答

按照接受的答案中的建议,通过创建一个转换流,我让它工作了。

我的直播是这样的:

var arraystream = new stream.Transform({objectMode: true});
arraystream._hasWritten = false;


arraystream._transform = function (chunk, encoding, callback) {
    console.log('_transform:' + chunk);
    if (!this._hasWritten) {
        this._hasWritten = true;
        this.push('[' + JSON.stringify(chunk));

    } else {
        this.push(',' + JSON.stringify(chunk));
    }
    callback();
};

arraystream._flush = function (callback) {
    console.log('_flush:');
    this.push(']');
    callback();

};

以及使用它的代码:

OutDataModel.find().stream().pipe(arraystream).pipe(res);

谢谢。

【问题讨论】:

  • 听起来您正在解决一个按预期工作的功能,因为预期的消费者(准备消费大量数据的应用程序)不会等待数组完成(它可能某些服务永远不会完成)。在这种情况下,使用堆栈即时解析各个 json 块将非常容易。话虽如此,我不确定您的应用有什么要求。
  • @AlexMa,感谢您的评论。我会在问题中澄清这一点,因为这个方法确实会有很多并发调用,但它们每个都不会返回大量数据。

标签: arrays json node.js rest node.js-stream


【解决方案1】:

我在这里找到了一个非常简单干净的解决方案:convert mongoose stream to array

这是我的简化版代码:

Products
    .find({})
    .lean()
    .stream({
        transform: () => {
            let index = 0;
            return (data) => {
                return (!(index++) ? '[' : ',') + JSON.stringify(data);
            };
        }() // invoke
    })
    .on('end', () => {
        res.write(']');
    })
    .pipe(res);

【讨论】:

    【解决方案2】:

    通过实现自己的逻辑,您走在了正确的轨道上。您也可以在这里使用ArrayFormatter,它正在做类似的事情:https://gist.github.com/aheckmann/1403797

    transform 函数会在每个文档上单独调用——Mongoose QueryStream 会为每个“数据”事件发出一个文档,但 QueryStream 并未在语义上将它们视为任何更大的数组数据结构的一部分;要获得数组格式的 JSON,您确实必须自己动手(正如您所推测的那样)。

    【讨论】:

    • 我尝试了与您建议的链接类似的方法,终于让它工作了。我正在用解决方案更新问题,以防有人需要它
    猜你喜欢
    • 2013-11-04
    • 2021-10-12
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    • 2012-08-08
    • 2023-03-04
    • 1970-01-01
    • 2017-09-17
    相关资源
    最近更新 更多