node.jsmongodbexpressmongoose

What causes Mongoose `updateMany` to return `{ acknowledged: false }`


I'm trying to set up notifications for an Express app using MongoDB.

I have an API endpoint where I $push a user's id to the readBy field in MongoDB to "mark" it as read after retrieving a user's notifications. When I make a request to this endpoint, it returns 200 and their notifications, but it isn't making any updates to the notification document in MongoDB. console.loging the query response in the callback gave me { acknowledged: false }. According to the Mongoose docs, acknowledged is a Boolean indicating everything went smoothly, but information about what acknowledged is and at which point in the query/write process caused it to occur was sparse. Since it didn't return any errors I couldn't find a way to troubleshoot it.

Would someone be able to shed some light on what exactly acknowledged: false is and in what typically causes it, and why it doesn't throw an error.

Model:

const notificationSchema = new Schema({
  timestamp: {
    type: Date,
    required: true
  },
  type: {
    type: String,
    required: true,
    enum: [
      'newCustomer',
      'contractSigned',
      'invoicePaid',
      'warrantyExp',
      'assignedProject'
    ]
  },
  recipients: [{
    type: Schema.Types.ObjectId,
    ref: 'Employee',
    required: true,
  }],
  customer: {
    type: Schema.Types.ObjectId,
    ref: 'Customer',
    required: true,
  },
  readBy: [{
    type: String
  }],
  uuid: {
    type: String,
    default: uuid.v4,
    immutable: true,
    required: true,
  },
  company: {
    type: Schema.Types.ObjectId, ref: 'Company'
  }
});

Route:

router.get("/notification/all", withAuth, async (req, res) => {
  const FOURTEEN_DAYS = new Date().setDate(new Date().getDate() + 14);
  try {
    const { uuid, userId } = req.loggedInUser;

    // Fetch notifications that have the user as a recipient.
    Notification.find({
      recipients: userId,
    })
      .populate("customer")
      .exec((err, notifs) => {
        if (err)
          return res.status(500).json({
            success: false,
            message: "Error: Failed to retrieve notifications.",
          });

        const result = [];
        const notifIds = [];

        for (const notif of notifs) {
          // Filter notif
          result.push({
            timestamp: notif.timestamp,
            customer: notif.customer,
            type: notif.type,
            read: notif.readBy.includes(uuid),
          });
          // Add the user as read
          notifIds.push(notif.uuid);
        }

        console.log(notifIds);

        /* THIS RETURNS ACKNOWLEDGED: FALSE */         
        // Write to DB that user has read these notifications
        Notification.updateMany(
          { uuid: { $in: notifIds } },
          { $push: { readBy: uuid } },
          (err, resultUpdate) => {
            if (err)
              return res.status(500).json({
                success: false,
                message:
                  "Error: Failed to add check off notifications as read.",
              });

            console.log(resultUpdate);

            // Delete notifications past 14 days and has been read by all recipients
            Notification.deleteMany(
              {
                timestamp: { $gte: FOURTEEN_DAYS },
                $expr: {
                  $eq: [{ $size: "$readBy" }, { $size: "$recipients" }],
                },
              },
              (err) => {
                if (err)
                  return res.status(500).json({
                    success: false,
                    message: "Error: Failed to delete old notifications.",
                  });

                return res.status(200).json({
                  success: true,
                  notifications: result,
                  message: "Fetched notifications",
                });
              }
            );
          }
        );
      });
  } catch (err) {
    res.status(500).json({ success: false, message: err.toString() });
  }
});

Solution

  • So it turns out that this issue was unrelated to write concern. acknowledged: false was being returned because the value we were trying to $push was undefined. So essentially Mongoose was refusing to write undefined values, but doesn't throw an error for the input value being undefined. Putting this here in case someone else runs into this issue.