简体   繁体   English

node.js将json的流数组转换为响应

[英]node.js stream array of json to response

I have a REST method that should return a JSON array with certain elements that are read from mongodb (using mongoose). 我有一个REST方法应该返回一个JSON数组,其中包含从mongodb读取的某些元素(使用mongoose)。

It should be very simple (in the real case the find method has arguments, but that's no the problem): 它应该非常简单(在实际情况下,find方法有参数,但这不是问题):

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

The problem with this approach is that I don't get a valid JSON as the result is like this : 这种方法的问题是我没有得到有效的JSON,因为结果是这样的:

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

and I was expecting this : 我期待着这个:

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

I have not been able to find a solution, but I am pretty sure there will be a simple one. 我一直无法找到解决方案,但我很确定会有一个简单的解决方案。

What I've tried : 我尝试过的:

Nothing that I'm proud of but here it goes. 没有什么我为此感到自豪,但在这里它。

  1. before streaming write '[' to the response. 在流式传输之前写'['到响应。
  2. Instead of JSON.stringify I provided another method that calls JSON.stringify and adds a ',' at the end 我提供了另一种调用JSON.stringify并在末尾添加','方法,而不是JSON.stringify
  3. in the 'end' event of the stream, I write ']' to the response. 在流的'end'事件中,我在响应中写']'

Still is not working with this "solution" as I have a trailing comma at the end like this : 仍然没有使用这个“解决方案”,因为我最后有一个尾随的逗号,如下所示:

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

As I said I am pretty sure there should be a clean solution as it is something that should be quite common. 正如我所说,我很确定应该有一个干净的解决方案,因为它应该是非常常见的。

There will be a lot of concurrent invocations to this method, so I don't want to read everything into memory and then write everything to the response. 这个方法会有很多并发调用,因此我不想将所有内容都读入内存,然后将所有内容写入响应。 Each of the invocations will not return a lot of records, but all of them together can be huge. 每个调用都不会返回很多记录,但所有这些记录都可能很大。 The consumer is a java application with spring, using jackson to parse the JSON. 使用者是一个带有spring的java应用程序,使用jackson来解析JSON。

Please let me know how to do it. 请让我知道怎么做。

ANSWER 回答

I got it working, by creating a Transform stream as was suggested in the accepted answer. 我通过按照接受的答案中的建议创建了一个转换流来实现它。

My stream looks like this : 我的流看起来像这样:

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();

};

and the code to use it : 以及使用它的代码:

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

Thanks. 谢谢。

You're on the right track by implementing your own logic. 通过实施自己的逻辑,你走在正确的轨道上。 You could also make use of the ArrayFormatter here which is doing something similar: https://gist.github.com/aheckmann/1403797 你也可以在这里使用ArrayFormatter做类似的事情: httpsArrayFormatter

The transform function gets called on each document individually -- a Mongoose QueryStream emits a single document per 'data' event but QueryStream isn't treating them semantically as part of any larger array data structure; 转换函数分别在每个文档上调用 - 一个Mongoose QueryStream每个'data'事件发出一个文档,但是QueryStream没有在语义上将它们视为任何更大的数组数据结构的一部分; to get an array-formatted JSON, you really do have to do it yourself (as you have surmised). 要获得一个数组格式的JSON,你真的必须自己做(如你所推测的那样)。

I found a very simple and clean solution here: convert mongoose stream to array 我在这里找到了一个非常简单和干净的解决方案: 将mongoose流转换为数组

That's my simplified version of the code: 这是我的简化版代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM