Matt Miller
Matt Miller

Reputation: 27

How do you conduct multiple queries and send all data to a template for rendering in a single res.render?

I have a MongoDB database called Critterpedia that contains 3 collections: fish, bugs, sea creatures. I am trying to query those collections to render the critters that will be leaving this month. Below is my fish collection query that works and renders. How do I conduct the same query for the other two collections but send all the data at once with a single res.render() call?

app.get('/critters', (req, res) => {
    let query = {$and: [{fishMonthsNorth: thisMonth}, {fishMonthsNorth: {$ne: nextMonth}}]}
     
    //Find all fish that leave this month
    Fish.find(query, (err, thisMonthFish) => {
        if (err) { 
            console.log(err);
        } else {
            res.render('index', {thisMonthFish : thisMonthFish});
        }
    }); 
});

Ideally I would like to:

//Query fish collection
//Query Bugs collection
//Query Sea collection
//res.render('index', {fish : fish, bugs : bugs, sea : sea});

Thank you in advance!

Upvotes: 1

Views: 154

Answers (1)

AlexZeDim
AlexZeDim

Reputation: 4352

Well, pretty easy, you wouldn't even believe.

Instead of writing a huge Model.aggregation query with $merge and $lookups, you could make 3 .find at once (in parallel), via Promise.all, Promise.allSettled or for await of

const express = require('express');
const router = express.Router();

/**
 * Model importing / Collections
 */

const fish_db = require("../../db/fish_db");
const bug_db = require("../../db/bug_db");
const sea_db = require("../../db/sea_db");

router.get('/critters', async function(req, res) {
    try {
        let response = {};
        /**
        * You could form / pre-determine more queries, for each of your collection
        */
        let query = {$and: [{fishMonthsNorth: thisMonth}, {fishMonthsNorth: {$ne: nextMonth}}]};
        /**
        * Promise.allSettled is ES2020 feature, you could use Promise.all instead
        * or for await of arrayOfPromises
        */
        await Promise.allSettled([
           fish_db.find(query).then(docs => { Object.assign(response, {fish: docs}) } )
           bug_db.find(query).then(docs => { Object.assign(response, {bug: docs}) } )
           sea_db.find(query).then(docs => { Object.assign(response, {sea: docs}) } )
        ])
        /** You could add almost anything to response if you want it to */
        await res.status(200).json(response);
    } catch (e) {
        await res.status(404).json(e);
    }
});

module.exports = router;

You could also form your array of promises before, like:

let futureFinds = [];

if (need to search for fish) {
    futureFinds.push(await fish_db.find(query))
}

if (need to search for bugs) {
    futureFinds.push(await bugs_db.find(query))
}

const [result_one, result_two] = await Promise.all(futureFinds)

and then handle them at-once as you see in code above.

Upvotes: 1

Related Questions