Hello, I am trying to use Aggregate pipeline in a node.js router
The aggregation gives me the perfect result in MongoDB Compass:
_id:61b1da8abab5f8eefe9e1589
sublinkid:2
sublinkicon:"fas fa-building"
sublinkname:"NewCo"
sublinkurl:"newco"
I then exported the pipeline to node and created function:
const db = require('../config/keys')
const getMenuItem = async () => {
const pipeline = [
{
'$unwind': {
'path': '$sublinks'
}
}, {
'$match': {
'$and': [
{
'menuitemname': 'Dashboard'
}, {
'sublinks.sublinkid': 1
}
]
}
}, {
'$project': {
'_id':0,
'menuitemname': '$menuitemname',
'menuitemicon': '$menuitemicon',
'sublinkid': '$sublinks.sublinkid',
'sublinkicon': '$sublinks.sublinkicon',
'sublinkname': '$sublinks.sublinkname',
'sublinkurl': '$sublinks.sublinkurl'
}
}
]
const result = db.collection("adminnavbar").aggregate(pipeline);
result.next(function(err, res) {
console.log(res)
})
}
module.exports = getMenuItem
then I created a router.get:
router.get('/updatemenuitem/:id', (req, res) => {
const menudetail = getMenuItem()
console.log(menudetail)
})
although I call the function first, the console.log in the router gives an error and afterwards the console.log from the function returns the result. Could anyone help, the console log in the router should give the result of the function… thank you very much (I only started working with MongoDB 8 weeks ago, VERY happy with it!)
Hello @Herman_Van_Looveren, welcome to the MongoDB forum!
Tour aggregation code:
const result = db.collection("adminnavbar").aggregate(pipeline);
result.next(function(err, res) {
console.log(res)
})
Change it to:
const result = await db.collection("adminnavbar").aggregate(pipeline);
const resultAsArray = await result.toArray();
return resultAsArray;
As you see I have converted the aggregation result, a cursor, to a JavaScript array.
The router#get
is changed to:
router.get('/updatemenuitem/:id', async (req, res) => {
const menudetail = await getMenuItem()
console.log(JSON.stringify(menudetail))
})
This should work fine, assuming the web server is up and running, and have a working database connection.
Thank you so much! This is a big step forward thanks to your help. On more question (because I am not so experienced…)
I now try to add this to the route:
router.get('/updatemenuitem/:id', async (req, res) => {
const menudetail = await getMenuItem()
let menufields = JSON.stringify(menudetail)
console.log(`This works: ` + menufields)
res.render('backoffice/updatemenuitem', {
menufields: menufields
})
})
The console log is perfect, but then I try to add this to the res.render, in the page I use EJS
<%= menufields.sublinkname %>
no error and the console log JSON.stringify(menudetail) works:
Server listening on port 5000
This works: [{"_id":"61b1da8abab5f8eefe9e1588","menuitemname":"Dashboard","menuitemicon":"fas fa-tachometer-alt","sublinkid":1,"sublinkicon":"fas fa-chart-line","sublinkname":"Overview","sublinkurl":"dashboard"}]
but the value does not appear on the page 'backoffice/updatemenuitem, I tried different values:
<%= menufields.sublinkname %>
<%= sublinkname %>
but nothing seems to work?
thanks for helping!
@Herman_Van_Looveren, please try this one:
router.get('/updatemenuitem/:id', async (req, res) => {
const menudetail = await getMenuItem()
let menufields = (menudetail.length > 0) ? menudetail[0] : {}
console.log(`This works: ` + menufields)
res.render('backoffice/updatemenuitem', {
menufields: menufields
})
})
WOW it works, thank you very much Prasad Saya! The aggregate pipelines look like a great tool.
One more question…
If I do the route like this, with hardcoded arguments it works fine:
router.get('/updatemenuitem/:sublinkid&:menuitemname', async (req, res) => {
const menudetail = await getMenuItem(1, 'Dashboard')
let result = (menudetail.length > 0) ? menudetail[0] : {}
console.log(result)
console.log(menudetail)
res.render('backoffice/updatemenuitem', {
menufields: result
})
})
but if I use the req.params it does not work
router.get('/updatemenuitem/:sublinkid&:menuitemname', async (req, res) => {
const menudetail = await getMenuItem(req.params.sublinkid, req.params.menuitemid)
let result = (menudetail.length > 0) ? menudetail[0] : {}
console.log(result)
console.log(menudetail)
res.render('backoffice/updatemenuitem', {
menufields: result
})
})
Or if I try this, no result:
router.get('/updatemenuitem/:sublinkid&:menuitemname', async (req, res) => {
const sublinkid = req.params.sublinkid
const menuitemname = req.params.menuitemid
const menudetail = await getMenuItem(sublinkid, menuitemname)
let result = (menudetail.length > 0) ? menudetail[0] : {}
console.log(result)
console.log(menudetail)
res.render('backoffice/updatemenuitem', {
menufields: result
})
})```
still no result either,
thanks
Hello Herman, you can try this:
router.get('/updatemenuitem/:sublinkid/:menuitemname', async (req, res) => {
const sublinkid = req.params.sublinkid
const menuitemname = req.params.menuitemid
console.log(sublinkid, menuitemname) // for verification
const menudetail = await getMenuItem(parseInt(sublinkid), menuitemname)
...
And, from the client you need to pass the values as:
http://www.example.com/updatemenuitem/sublinkid/menuitemname
This should work 
1 Like
Thanks Prasad Saya! It works indeed, my mistake was forgetting the parseInt(). Great Help!