3
\$\begingroup\$

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 id
  • response is an object that contains the event's ObjectId, the employee event response (value), and an updateEvent boolean flag
  • notes are employee event notes
  • userId (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?

  1. No Event employeeResponses sub documents exists for the logged in employee, create them
  2. One or many Events don't contain employeeResponses sub documents for the logged in employee, create them
  3. One or many Events already contain employeeResponses sub documents for the logged in employee, update them.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.