I am writing a MERN web application. This particular page is focused on recording demerits that have been accrued by students. I have many different models that interact with each other, but in this case I need the following to interact:
const demeritReportInstanceSchema = new mongoose.Schema({
user : {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
...
})
const userSchema = new mongoose.Schema({
...
fName: {
type: String,
required: true
},
lName: {
type: String,
required: true
},
...
})
whereas when the table is displayed, it currently looks like this:
user | offenseDate | period | infractionCode | punishingOfficial |
---|---|---|---|---|
(this is a user ObjectID) 65c5480f6b1bcdbcee2491aa | Feb 2, 2024 | 1 | another objectID | another user ObjectID |
I need it it look like:
user | offenseDate | period | infractionCode | punishingOfficial |
---|---|---|---|---|
lName, fName | Feb 2, 2024 | 1 | M11012 | lName, fName |
I have been following this tutorial: https://www.youtube.com/watch?v=CvCiNeLnZ00&t=12778s&ab_channel=DaveGray (ref: chapter 7) in which Dave has a Note and User model (backend) like the following:
const noteSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
...
})
const userSchema = new mongoose.Schema({
username: {
type: String,
required: true
},
})
that displays the username in a similar table as what I have (frontend) by:
Note.js
return (
<tr className="table__row">
...
<td className="table__cell note__username">{note.username}</td>
...
</tr>
)
NotesList.js
if (isSuccess) {
const { ids } = notes
const tableContent = ids?.length
? ids.map(noteId => <Note key={noteId} noteId={noteId} />)
: null
content = (
<table className="table table--notes">
<thead className="table__thead">
<tr>
...
<th scope="col" className="table__th note__username">Owner</th>
...
</tr>
</thead>
<tbody>
{tableContent}
</tbody>
</table>
)
}
Any help would be greatly appreciated.
Using {demerit.user} provides me with the ID of the user as displayed above. Using {demerit.user.fName}, {demerit.user.lName} provides me with " , " in the cell of the table, and does not return its attributes. I have been examining how to use Model.populate from Mongoose: https://mongoosejs.com/docs/populate.html but I do not know where I would place populating queries - in the frontend, or the backend with the model?
To make this easy for you implement, I have had a look at the tutorial and the author seems to be importing the models into a controller and making custom query functions to the database then using them inside each route handler. Therefore following the pattern adopted in the tutorial your code might look something like:
const Demerits = require('../models/Demerits'); //< or whatever this model is called
const User = require('../models/User');
const asyncHandler = require('express-async-handler');
const getAllDemerits = asyncHandler(async (req, res) =>{
const demerits = await Demerits.find().populate('user').lean();
if(!demerits){
return res.status(400).json({message: 'No demerits found'});
}
res.json(demerits);
})
Here populate('user')
is what swaps the ObjectId
for the full User
documents and will allow you to access user.fName
and user.lName
in your front-end.