【问题标题】:Streaming responses from MongoDB to client via Hapi通过 Hapi 将响应从 MongoDB 流式传输到客户端
【发布时间】:2023-03-02 21:41:01
【问题描述】:

通过 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,无法解析。

我尝试将此流通过管道传输到事件流模块的 .join('\n') 流中以添加换行符,同时还在构建字符串化 JSON 数组之前和之后推送字符串“[”和“]” ,但还没有成功。无论如何,这感觉太hacky了。

有没有更好的办法?

【问题讨论】:

    标签: json node.js mongodb stream hapijs


    【解决方案1】:

    必须使用流转换发送有效的 JSON。

    基本上你必须:

    1. '['开始直播

    2. 然后追加stringified JSON object

    3. 在每个对象之后添加','

    4. ']'结束流

    因此在流中接收到的最终结果将是有效的 JSON,例如

    [
    {'key': 'value'}, 
    {'key': 'value'},
    ]
    

    一些解决方案:

    http://andyfiedler.com/2017/01/mongodb-stream-to-hapi

    https://github.com/nlindley/hapi-mongo-stream

    https://github.com/dominictarr/JSONStream

    【讨论】:

      【解决方案2】:

      这是我如何将 Mongo 与 Hapi 一起使用的示例。

      来自 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);
                          });
                  }
              }
          }
      };
      

      【讨论】:

      • 但是这种方法没有使用流。我认为 toArray 将所有查询的文档加载到内存中,然后一次将它们全部返回。我希望能够在通过游标流找到第一个文档后立即返回它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-31
      • 2014-12-21
      • 2018-07-15
      • 2012-04-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多