Search code examples
node.jsmongodbaggregateresponsemiddleware

NodeJS,MongoDB - Return a JSON response from aggregate inside a GET request


I created an aggregate pipeline that returns many documents from my database.I can also see the results using "console.log" .But i can't return the results in a response when i am using Postman.You can test it on PostMan using AreaName=Hungary,Resolution=PT15M,Year=2018,Month=1,Day=1



var express = require('express');
var router = express.Router();
var assert = require('assert')
const URL = 'mongodb+srv://user:[email protected]/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;

-> above code gives returns a json and then the server crushes

I can see the restults of " cursor.forEach(doc => { console.log(doc)}) " in the terminal and this seems to be working ok.What i am asking is how to return a response in json.Something like " res.json(cursor) " I tried some different functions/methods to do this but none seems to work.

Update After an answer i tried this

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

The above code when tested with Postman returns 1 json document from the database.The problem is that it returns only one and then the server crashes.The documents i want to return are multiple. The error message is Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client


Solution

  • You need to call .toArray() method to return all results.

    EDIT: Debugged the code. Changed Route to App

    var express = require('express');
    var app = express();
    
    var router = express.Router();
    var assert = require('assert')
    const URL = 'mongodb+srv://user:[email protected]/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: Result