NodeJS, MongoDB - вернуть JSON ответ от агрегата внутри запроса GET - PullRequest
0 голосов
/ 06 января 2020

Обновление 2 После множества комментариев я решил загрузить свою полную статистическую функцию + доступ к моей БД в атласе (БД используется только для целей тестирования, так что все в порядке)

Я создал агрегатный конвейер, который возвращает много документов из моей базы данных. Я также могу увидеть результаты, используя "console.log". Но я не могу вернуть результаты в ответ, когда использую Postman. Вы можете проверить его на PostMan с использованием AreaName = Венгрия, разрешение = PT15M, год = 2018, месяц = ​​1, день = 1



var express = require('express');
var router = express.Router();
var assert = require('assert')
const URL = 'mongodb+srv://user:user@cluster0-0pwss.mongodb.net/test?retryWrites=true&w=majority'
const MongoClient = require('mongodb').MongoClient
//const CircularJSON = require('circular-json');
//const {parse, stringify} = require('flatted/cjs');



router.get('/:AreaName/:Resolution/:Year/:Month/:Day', (req, res, next) => {
  const _AreaName=req.params.AreaName
  const _Resolution=req.params.Resolution
  const _Year = parseInt(req.params.Year)
  const _Month = parseInt(req.params.Month)
  const _Day = parseInt(req.params.Day)

  MongoClient.connect(URL,{
    useNewUrlParser: true,
    useUnifiedTopology: true}, 
    async (err, client) => {
      if (err) throw err; 
      else console.log('connected to db');
      assert.equal(null, err) 
      const db = client.db('energy')
      var collection = db.collection('ActualTotalLoad')
      const agg = [
        { 
          $match : 
          {
            AreaName: _AreaName,
            Day : _Day,
            Month: _Month,
            Year: _Year
          }
      },

        {
          $lookup:
          {
            from: 'ResolutionCode',
            localField: 'ResolutionCodeId',
            foreignField : 'Id',
            as: "resolution_codes"
          }
        },
        {
          $unwind: {path : "$resolution_codes"}
        },

        { 
          $match : {'resolution_codes.ResolutionCodeText' : _Resolution}
        },
        {
          $addFields : {ResolutionCode : '$resolution_codes.ResolutionCodeText',
                        Source :'entso-e',
                        Dataset :'ActualTotalLoad'
        }
        },

        {
          $project : 
          {
            _id:0,
            Id : 1,
            ResolutionCodeId:1,
            Source : 1,
            AreaName: 1,
            Year : 1,
            Month : 1,
            Day : 1,
            ResolutionCode : 1
          }
        }  
      ];
      var cursor = collection.aggregate(agg)
      cursor.forEach(doc => {
        console.log(doc)
      })


     await cursor.toArray((error, result) => {
        if(error) {
            return res.status(500).send(error);
        }
        cursor.forEach(doc => {
            res.send(doc)
          })

    });

  })// connection ends here
})
module.exports = router;

-> приведенный выше код возвращает значения json, а затем сервер прерывает

Я вижу остаток " cursor.forEach (do c => {console.log (do c)}) " в терминале, и это, кажется, работает нормально. Что я Я спрашиваю, как вернуть ответ в json. Что-то вроде " res. json (курсор) " Я пытался сделать несколько различных функций / методов, но ни одна из них не работает.

Обновление После ответа я попробовал это

cursor.toArray((error, result) => {
        if(error) {
            return res.status(500).send(error);
        }
        cursor.forEach(doc => {
            res.send(doc)
          })

    });

Приведенный выше код при тестировании d с почтальоном возвращает 1 json документ из базы данных. Проблема в том, что он возвращает только один, а затем происходит сбой сервера. Документов, которые я хочу вернуть, несколько. Сообщение об ошибке: Ошибка [ERR_HTTP_HEADERS_SENT]: невозможно установить заголовки после их отправки клиенту

Ответы [ 3 ]

1 голос
/ 06 января 2020

Пожалуйста, попробуйте это:

/* Frameworks Used + constants */
var express = require('express');
var router = express.Router();
var assert = require('assert')
const URL = 'an Atlas MongoDB'
const MongoClient = require('mongodb').MongoClient


router.get('/base/:param1/:param2/:param3', (req, res, next) => {

    MongoClient.connect(URL, (err, client) => {
        assert.equal(null, err)
        const db = client.db('DB')
        db.collection('Collection').aggregate([{
            /* ... an aggregate with:  $lookup,$unwind,$match,$addFields,$project ..... */
        }]).toArray((err, resp) => {
            if (err) res.send({ error: err.message }); // (Or) res.status(400).end();
            if (resp.length) res.json(resp)
            res.send({ data: 'No docs found' })
        });
    })
})


module.exports = router;

(Или)

/* Frameworks Used + constants */
var express = require('express');
var router = express.Router();
var assert = require('assert')
const URL = 'an Atlas MongoDB'
const MongoClient = require('mongodb').MongoClient


router.get('/base/:param1/:param2/:param3', (req, res, next) => {

    MongoClient.connect(URL, async (err, client) => {
        if(err) res.send({ error: 'DB connectivity error' });
        try {
            assert.equal(null, err)
            const db = client.db('DB')
            let resp = await db.collection('Collection').aggregate([{
                /* ... an aggregate with:  $lookup,$unwind,$match,$addFields,$project ..... */
            }]).toArray();
            if (resp.length) res.json(resp)
            res.send({ data: 'No docs found' })
        } catch (error) {
            console.error('Error ::', error)
            //res.status(400).end(); (Or)
            res.send({ error: error.message });
        }
    })
})


module.exports = router;
1 голос
/ 06 января 2020

Раньше у меня была очень похожая проблема, и она возвращала само обещание. Если это массив обещаний, вы можете попробовать что-то вроде этого:

Promise.all(resp).then(values => res.json(values))

1 голос
/ 06 января 2020

Вам необходимо вызвать метод .toArray () , чтобы вернуть все результаты.

РЕДАКТИРОВАТЬ: Отладка кода. Изменено Route на App

var express = require('express');
var app = express();

var router = express.Router();
var assert = require('assert')
const URL = 'mongodb+srv://user:user@cluster0-0pwss.mongodb.net/test?retryWrites=true&w=majority'
const MongoClient = require('mongodb').MongoClient
//const CircularJSON = require('circular-json');
//const {parse, stringify} = require('flatted/cjs');

app.get('/', function (req, res) {
  res.send('Hello World!');
});

app.get('/:AreaName/:Resolution/:Year/:Month/:Day', (req, res) => {
  const _AreaName=req.params.AreaName
  const _Resolution=req.params.Resolution
  const _Year = parseInt(req.params.Year)
  const _Month = parseInt(req.params.Month)
  const _Day = parseInt(req.params.Day)

  MongoClient.connect(URL,{
    useNewUrlParser: true,
    useUnifiedTopology: true}, 
    async (err, client) => {
      if (err) throw err; 
      else console.log('connected to db');
      assert.equal(null, err) 
      const db = client.db('energy')
      var collection = db.collection('ActualTotalLoad')
      const agg = [
        { 
          $match : 
          {
            AreaName: _AreaName,
            Day : _Day,
            Month: _Month,
            Year: _Year
          }
      },

        {
          $lookup:
          {
            from: 'ResolutionCode',
            localField: 'ResolutionCodeId',
            foreignField : 'Id',
            as: "resolution_codes"
          }
        },
        {
          $unwind: {path : "$resolution_codes"}
        },

        { 
          $match : {'resolution_codes.ResolutionCodeText' : _Resolution}
        },
        {
          $addFields : {ResolutionCode : '$resolution_codes.ResolutionCodeText',
                        Source :'entso-e',
                        Dataset :'ActualTotalLoad'
        }
        },

        {
          $project : 
          {
            _id:0,
            Id : 1,
            ResolutionCodeId:1,
            Source : 1,
            AreaName: 1,
            Year : 1,
            Month : 1,
            Day : 1,
            ResolutionCode : 1
          }
        }  
      ];
      var cursor = collection.aggregate(agg)

      await cursor.toArray((error, result) => {
        if(error) {
            return res.status(500).send(error);
        }
        res.send(result);
    });

  })// connection ends here
})
module.exports = router;

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

Результат: Result

...