Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v8.8.3 save() on a model with discriminator misses nested schema timestamps #15088

Open
2 tasks done
tjann opened this issue Dec 10, 2024 · 3 comments · May be fixed by #15099
Open
2 tasks done

v8.8.3 save() on a model with discriminator misses nested schema timestamps #15088

tjann opened this issue Dec 10, 2024 · 3 comments · May be fixed by #15099
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.

Comments

@tjann
Copy link

tjann commented Dec 10, 2024

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Mongoose version

8.8.3

Node.js version

v22.8.0

MongoDB server version

v7.0.0

Typescript version (if applicable)

No response

Description

I noticed that my subdocuments were missing timestamps on v8.8.3 but not v8.8.2.

Per the documentation, Mongoose should set createdAt when the document is first inserted, and updatedAt should be added/updated whenever you update the document using save(), updateOne(), updateMany(), findOneAndUpdate(), update(), replaceOne(), or bulkWrite().

While trying to create a minimal reproducible example, I did notice that the presence of a discriminator on the top level schema is required to see the bug. I also noticed that when using .save(), the timestamps are not being updated, whereas updateOne() and findByIdAndUpdate() do update, even if I don't specify the discriminator field in the updateOne() filter. I did not test the other update operations.

Steps to Reproduce

Try the sample code using v8.8.2 and then with v8.8.3. Notice that the last console log only has timestamps when using v8.8.2.
Sample code (omitted the mongoose import and DB connection):

const Schema = mongoose.Schema;

const RequestTriggeredWorkflowSchema = new Schema(
  {
    workflow: {
      type: String,
    },
  },
  {
    timestamps: true,
  },
);

const RequestSchema = new Schema(
  {
    status: {
      type: String,
    },
    summary: {
      type: String,
    },
    triggeredWorkflows: [RequestTriggeredWorkflowSchema],
  },
  {
    discriminatorKey: 'source',
    timestamps: true,
  },
);

const EmailRequestSchema = new Schema({
  // Any extra properties that specifically apply to 'email' requests
});
const FormRequestSchema = new Schema({
  // Any extra properties that specifically apply to 'form' requests
});

const Request = mongoose.model('Request', RequestSchema);

Request.discriminator('Request:email', EmailRequestSchema, 'email');
Request.discriminator('Request:form', FormRequestSchema, 'form');

async function runValidationTest() {
  const request = new Request({
    status: 'new',
    source: 'form',
  });
  await request.save();

  let requestAsReadFromDb = await Request.findById(request._id);
  console.log('\nCreated request (looks good):', JSON.stringify(requestAsReadFromDb, null, 2));

  request.status = 'in progress';
  await request.save();

  requestAsReadFromDb = await Request.findById(request._id);
  console.log(
    '\nRequest after save() simple update (looks good):',
    JSON.stringify(requestAsReadFromDb, null, 2),
  );

  request.triggeredWorkflows.push({
    workflow: '111111111111111111111111',
  });
  await request.save();

  requestAsReadFromDb = await Request.findById(request._id);
  // This does not have timestamps when Request has discriminators.
  console.log(
    '\nRequest after save() updating nested schema with timestamp true (examine this!):',
    JSON.stringify(requestAsReadFromDb, null, 2),
  );

However, if you comment out the discriminator on Request, then the timestamps do show up in both versions.

Appendix: I used the following to verify that the issue is present on .save(), but not with findByIdAndUpdate or updateOne. I did not exhaustively test other operators.

  // The following always work (v8.8.2 or v8.8.3, with or without discriminators)

  // const foundByIdAndUpdatedRequest = await Request.findByIdAndUpdate(
  //   request._id,
  //   {
  //     triggeredWorkflows: [{ workflow: '222222222222222222222222' }],
  //   },
  //   { new: true },
  // );
  // console.log(
  //   'Request after updating nested schema with timestamp true using findByIdAndUpdate:',
  //   JSON.stringify(foundByIdAndUpdatedRequest, null, 2),
  // );

  // await Request.updateOne(
  //   { _id: request._id },
  //   {
  //     triggeredWorkflows: [{ workflow: '333333333333333333333333' }],
  //   },
  //   { new: true },
  // );
  // requestAsReadFromDb = await Request.findById(request._id);
  // console.log(
  //   'Request after updating nested schema with timestamp true using updateOne:',
  //   JSON.stringify(requestAsReadFromDb, null, 2),
  // );
}

runValidationTest();

Expected Behavior

I would expect that the behavior between v8.8.2 and v8.8.3 to be the same (include timestamps in subdocuments, even if the top level schema has discriminators), since there were no announced changes.

@maximilianschmid
Copy link

Same here

@kticka
Copy link

kticka commented Dec 13, 2024

It seems this might be related to my issue, #15092.

@maximilianschmid
Copy link

Mongoose 8.9 still has this issue.

@vkarpov15 vkarpov15 added the confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. label Dec 15, 2024
vkarpov15 added a commit that referenced this issue Dec 15, 2024
…o ensure $getAllSubdocs() can properly get all subdocs

Fix #15088
vkarpov15 added a commit that referenced this issue Dec 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Projects
None yet
4 participants