I have a series of Events (roughly 10-20 events that will be dynamically created per month):
Event Model:
import { Schema, model } from "mongoose";
const eventSchema = new Schema({
callTimes: { type: Array, of: Date, required: true },
eventDate: { type: Date, required: true },
employeeResponses: [
{
_id: {
type: Schema.Types.ObjectId,
ref: "User",
required: true,
},
response: { type: String, required: true },
notes: String,
},
],
scheduledEmployees: [
{
_id: {
type: Schema.Types.ObjectId,
ref: "User",
required: true
},
callTime: { type: Date, required: true },
},
],
});
export default model("Event", eventSchema);
Some sample data:
[
{
"_id": "5d5daaafcf11d95c0a75a023",
"callTimes": [
"2019-08-21T10:30:41-07:00",
"2019-08-21T11:00:41-07:00",
"2019-08-21T11:30:41-07:00"
],
"eventDate": "2019-08-20T02:30:36.000Z",
"employeeResponses": [],
"scheduledEmployees": []
},
{
"_id": "5d5b5ee857a6d20abf49db19",
"callTimes": [
"2019-08-19T17:15:43-07:00",
"2019-08-19T17:45:43-07:00",
"2019-08-19T18:15:43-07:00",
"2019-08-19T19:00:43-07:00"
],
"eventDate": "2019-08-21T02:30:36.000Z",
"employeeResponses": [
{
"_id": "5d5b5e952871780ef474807b",
"response": "Available to work.",
"notes": "I can work all day."
},
{
"_id": "5d5b5e952871780ef474807c",
"response": "Not available to work.",
"notes": "I have school during that time."
}
],
"scheduledEmployees": []
}
...etc
]
Employees can view a form that includes the current month's events and add their responses. However, I'm running into a predicament with creating/updating sub documents dynamically. I'm trying to create a bulkWrite
function that will either create an employeeResponse
sub document if none exists or update the sub document if it's already been created.
I came up with this function, where:
_id
contains the form idresponse
is an object that contains the event's ObjectId, the employee event response (value), and an updateEvent boolean flagnotes
are employee event notesuserId
(req.session.user.id) is the current logged in employee stored in an express-session
Update Event function:
const updateFormAp = async (req, res) => {
try {
const { _id, responses, notes } = req.body;
if (!_id || !responses) throw "Missing required update event parameters. You must include an event id and response.";
const formExists = await Form.findOne({ _id });
if (!formExists) throw "Unable to locate that event form.";
// iterate over responses and update the Events accordingly...
await Event.bulkWrite(
responses.map(response => {
try {
const { id: eventId, value, updateEvent } = response;
const { id: userId } = req.session.user;
// if the employee response exists...
const filter = updateEvent
? {
// set the filter to event id + employee id
_id: eventId,
"employeeResponses._id": userId,
}
: {
// else set the filter to event id only
_id: eventId,
};
// if the employee response exists...
const update = updateEvent
? {
// update the sub document in place
$set: {
"employeeResponses.$.response": value,
"employeeResponses.$.notes": notes,
},
}
: {
// else add a new sub document
$push: {
employeeResponses: {
_id: userId,
response: value,
notes,
},
},
};
return {
updateOne: {
filter,
update,
},
};
} catch (error) {
throw error;
}
}),
);
res
.status(201)
.json({ message: "Successfully added your responses to the A/P form!" });
} catch (err) {
res
.status(400)
.json({ error: err.toString() });
}
};
So, if an event was added after some responses were recorded, the employee can go back and add their response to this newly created event while optionally updating their other responses as well.
Is there another or better approach to handling all 3 cases?
- No Event
employeeResponses
sub documents exists for the logged in employee, create them - One or many Events don't contain
employeeResponses
sub documents for the logged in employee, create them - One or many Events already contain
employeeResponses
sub documents for the logged in employee, update them.