We are currently making a website for our roommate matching project. We are at the point where we are making the results page, which should display the 3 most compatible roommates based on some questions where the algorithm calculates their compatibility percentage.
We are now trying to pass the object called “fitness” that holds all of the results, which would be:
let fit = {
fitness: Math.round(sum * 100),
email: resident[i].email,
name: resident[i].firstName + " " + resident[i].lastName,
};
To our .ejs file called results.ejs. The fit object gets pushed into our global “fitness” variable.
This is our post request:
router.post("/results", function (request, response) {
let item = request.body;
let applicant_name = request.body.firstName;
client.connect(function (err) {
const db = client.db("myFirstDatabase");
assert.equal(null, err);
db.collection("residents").insertOne(item, function (err, result) {
assert.equal(null, err);
console.log("Item inserted");
});
});
client.connect(function (err) {
const db = client.db("myFirstDatabase");
assert.equal(null, err);
db.collection("residents")
.find({})
.toArray(function (err, resident) {
if (err) throw err;
/* weighting(request); */
compatability(request, resident);
});
});
client.close();
response.render("pages/results", {
applicant_name: applicant_name,
resident: fitness,
});
});
In our results.ejs file, we use Bootstrap cards in order to display the 3 most compatible roommates. This is the code we use in the results.ejs file:
<p class="card-text">
Compatibility %: <%= resident[0].fitness %><br />
Name: <%= resident[0].name %> <br />
Email: <%= resident[0].email %><br />
Location: <br />
</p>
Whenever we run the post request, we get an error saying “Cannot read properties of undefined (reading ‘fitness’)”, but if we refresh again, the Node.js server crashes, but it displays the actual values we want to get. If we add a “?” after “resident[0]”, it runs the page without any errors but does not display any information from the object. We have tried numerous things but cannot find the right solution to solve this issue. Thanks in advance.
EDIT
The whole code from the .ejs file and our serverside code, with photos of how it looks on the website: https://pastebin.com/zRxdk6aq
Advertisement
Answer
The error "Cannot read properties of undefined (reading 'fitness')"
in this case means that resident[0]
is undefined. This is probably due to the fact that resident
is either undefined or is an empty array (length 0).
From the code you provided I can’t see, where you actually push your object into the global fitness variable or where the variable is defined. Maybe that’s were the problem is. To help you further with that, it would certainly help if you could post the code for that.
Edit: Looking at the new code you provided in your pastebin, it looks like you’re using asynchronus functions but are expecting a synchronus behaviour. Your current code looks essentially like this:
router.post("/results", function (request, response) {
client.connect(function (err) {
// Insert data into db
});
client.connect(function (err) {
// Fetch data from db
});
client.close();
response.render("pages/results", {
applicant_name: applicant_name,
resident: fitness,
});
});
The problem with that is, that your program does not wait for your DB-operations to finish before rendering your page. This is because of how callback functions work.
I presume you are using the mongoDB driver for nodejs. Besides classic callback options, it also allows for the use of async/await:
router.post("/results", async (request, response) {
//
await client.connect();
const db = client.db('myFirstDatabase');
await db.collection("residents").insertOne(request.body);
let residents = await db.collection("residents").find({}).toArray();
let fitness = compatability(request, resident);
client.close();
response.render("pages/results", {
applicant_name: request.body.firstName,
resident: fitness,
});
});
function compatability(request, resident) {
let fitness = [];
// Do your calculations here
return fitness;
}
This way your request handler waits until you inserted your new item into the db and fetched the existing ones. Only after that, it renders your page and thereby ensures, that the fitness
variable is already filled with data.
Note that in this example I also suggest to change your compatability function so that it returns your `fitness´ variable instead of making it global.
If you aren’t familiar with async/await I recommend that you also try to learn about Promises.