Here is the original code
import type { NextApiRequest, NextApiResponse } from "next"
import { MongoClient } from "mongodb"
import { getSession } from "next-auth/client"
export type Message = {
message: string
}
const uri = process.env.MONGODB_URI
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "GET") {
const client = await MongoClient.connect(uri!)
const db = client.db()
const results = await db
.collection("questions")
.aggregate([{ $sample: { size: 5 } }])
.toArray()
// removes _id from each question object
const cleanedResults = results.map(questionObj => {
return {
category: questionObj.category,
type: questionObj.type,
difficulty: questionObj.difficulty,
question: questionObj.question,
correct_answer: questionObj.correct_answer,
incorrect_answers: questionObj.incorrect_answers
}
})
client.close()
res.status(200).json(cleanedResults)
}
// end handler function
}
First pass at amount. Note the default must be 5 because that is set in some front-end code as of now.
let amount: any
if (req.query.amount) {
amount = parseInt(`${req.query.amount}`)
} else {
amount = 5
}
const db = client.db()
const results = await db
.collection("questions")
.aggregate([{ $sample: { size: amount } }])
.toArray()
Search by category not just number:
const results = await db
.collection("questions")
.aggregate([{ $sample: { size: amount } }, { $match: { category: "sports" } }])
.toArray()
But how to use all if there is not a category passed as a query parameter? I need this for the default value. I thought it might be -1 but that is incorrect. Could we just wrap this in logic that says “if there is a passed query parameter?” I couldn’t get that to work with a template literal, (error like “type string is not assignable to type document). Looks like an empty object works.
// set a default for amount
// if a query parameter is passed then use that
let amount: any = 5
if (req.query.amount) {
amount = parseInt(`${req.query.amount}`)
}
// set a default for categoryMatch
// if a query parameter is passed then use that
let category: string | string[]
let categoryMatch = {}
if (req.query.category) {
category = req.query.category
categoryMatch = { category: `${category}` }
}
const db = client.db()
const results = await db
.collection("questions")
.aggregate([{ $sample: { size: amount } }, { $match: categoryMatch }])
.toArray()
Not working so great. Category of sports is only pulling one question. Submitting again we eventually get an empty array.
Order of operations. When using aggregate the documents that are output from one stage are input to the next stage. If we pull random first then the category we will be pulling fr.the results of random. I’m confident this was the issue.
I don’t think it matters in what order you put in the query string but I do think it matters the order that you put in the aggregate operation.
I think the variables are not getting cleared.
If there are no query params, it’s an empty object.
Should I be using find versus aggregate?
Are the and/or conditions accurate?
if you type a category that doesn’t exist into the search bar we get an empty array. This needs better error handling.
Query parameters are set automatically, and we have default values set. What we want to do is update the defaults with input selections.