通过Hapi将MongoDB的流响应传输到客户端

4
什么是通过Hapi流式传输MongoDB查询响应到客户端的最佳方法?我看过一些使用http或request的示例,但没有使用hapi的。问题在于客户端上得到的是连接和字符串化的JSON对象,但我不能对结果调用JSON.parse,因为它们在一起不是有效的JSON。一些解决方案建议在发送到客户端之前在服务器端进行连接,但这似乎有违流的价值。例如:
const Hapi = require('hapi'),
  MongoClient = require('mongodb').MongoClient,
  Readable = require('stream').Readable;

// Connection url
const url = 'mongodb://localhost:27017/test';

// Create a server with a host and port
const server = new Hapi.Server();
server.connection({
  host: 'localhost',
  port: 8000
});

// Add the route
server.route({
  method: 'GET',
  path: '/stream',
  handler: function (request, reply) {

    let docs = [{ a: 1, b: 1 }, { a: 2, b: 2 }, { a: 3, b: 3 }, { a: 4, b: 4 }];

    // Connect using MongoClient
    MongoClient.connect(url, (err, db) => {
      // Create a collection we want to drop later
      const col = db.collection('stream_example');

      // Insert documents into collection
      col.insertMany(docs, { w: 1 }, function (err) {
        if (err) return console.log(err);

        // Peform a find to get a cursor
        const stream = col.find()
          .stream({
            transform: function (doc) {
              return JSON.stringify(doc);
            }
          });

        reply(new Readable().wrap(stream));
      });
    });
  }
});

// Start the server
server.start(err => {
  if (err) {
    throw err;
  }
  console.log('Server running at:', server.info.uri);
});

返回一个response.result,其中包含以下内容:
"{"_id":"57b0b99d681bb97a9321f03e","a":1,"b":1}{"_id":"57b0b99d681bb97a9321f03f","a":2,"b":2}{"_id":"57b0b99d681bb97a9321f040","a":3,"b":3}{"_id":"57b0b99d681bb97a9321f041","a":4,"b":4}"
这是无效的JSON格式,无法解析。
我尝试将此流导入event-stream模块的.join('\n')流以添加换行符,并在前后推送字符串化的“ [”和“ ]”以构建字符串化的JSON数组,但尚未成功。无论如何,这种方法似乎太过取巧。
有更好的方法吗?
2个回答

0

-4

这是我如何在Hapi中使用Mongo的示例。

来自BoardRepo.js:

module.exports = {    
    GetAllBoards: function (facility) {
        return new Promise(function (resolve, reject) {
            var db = mongo.ETestDatabase;
            db.collection('boards').find({ "Location.Facility": facility }).toArray().then(r => {
                resolve(r);
            }).catch(err => {
                logger.error('Error getting all boards by facility - ' + err.message);
                reject(err.message);
            });
        });
    }
};

在 Hapi 处理程序 (BoardHandler.js) 中:
module.exports = {    
    GetAllBoards: {
        method: 'GET',
        path: '/v1/boards/facility/all/{facility}',
        config: {
            auth: 'jwt',
            plugins: { 'hapiAuthorization': { roles: ['ADMINISTRATOR', 'MANAGER', 'TECHNICIAN', 'OPERATOR'] } },
            description: 'Gets all boards per facility',
            tags: ['api'],
            handler: (request, reply) => {
                logger.info('[' + request.auth.credentials.username + '] GetAllBoards requested');
                var facility = request.params.facility;
                repo.GetAllBoards(facility)
                    .then(boards => {
                        if (boards !== null) {
                            reply(boards);
                        } else {
                            reply().code(404);
                        }
                    })
                    .catch(err => {
                        geh.HandleError(request.auth.credentials.username, err, reply);
                    });
            }
        }
    }
};

1
但是这种方法没有利用流。我认为toArray会将所有查询的文档加载到内存中,然后一次性返回它们。我希望能够通过游标流在找到第一个文档时立即返回它。 - Jared_C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接