Skip to content

StrictModeError with embedded discriminator .update() bug #9093

@andreialecu

Description

@andreialecu

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

Apologies if I'm missing something obvious.

When using an embedded discriminator, schema validation does not take into account discriminated schemas, resulting in the inability of updating subdocuments unless setting strict: false.

If the current behavior is a bug, please provide the steps to reproduce.

"use strict";
const mongoose = require("mongoose");
const { Schema } = mongoose;
const assert = require("assert");

mongoose.set("debug", true);

run()
  .then(process.exit)
  .catch(console.error);

async function run() {
  await mongoose.connect(
    "mongodb://localhost:27017,localhost:27018,localhost:27019/test?replicaSet=rs",
    {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    },
  );

  await mongoose.connection.dropDatabase();
  var eventSchema = new Schema(
    { message: String },
    { discriminatorKey: "kind", _id: false },
  );

  var batchSchema = new Schema({ events: [eventSchema] });

  // `batchSchema.path('events')` gets the mongoose `DocumentArray`
  var docArray = batchSchema.path("events");

  // The `events` array can contain 2 different types of events, a
  // 'clicked' event that requires an element id that was clicked...
  var clickedSchema = new Schema(
    {
      element: {
        type: String,
        required: true,
      },
    },
    { _id: false },
  );
  // Make sure to attach any hooks to `eventSchema` and `clickedSchema`
  // **before** calling `discriminator()`.
  var Clicked = docArray.discriminator("Clicked", clickedSchema);

  // ... and a 'purchased' event that requires the product that was purchased.
  var Purchased = docArray.discriminator(
    "Purchased",
    new Schema(
      {
        product: {
          type: String,
          required: true,
        },
      },
      { _id: false },
    ),
  );

  var Batch = mongoose.model("EventBatch", batchSchema);

  // Create a new batch of events with different kinds
  var batch = {
    events: [
      { kind: "Clicked", element: "#hero", message: "hello" },
      { kind: "Purchased", product: "action-figure-1", message: "world" },
    ],
  };

  await Batch.create(batch);

  mongoose.set("debug", true);

  await Batch.updateOne(
    { events: { $elemMatch: { element: "#hero" } } },
    { "events.$.element": "test" },
    { strict: "throw" }, // change to false and it works
  );

  const results = await Batch.find()
    .lean()
    .exec();
  console.dir(JSON.stringify(results), { depth: 1000 });
}

Results in error:

StrictModeError: Field `events.$.element` is not in schema and strict mode is set to throw.

What is the expected behavior?

Should not throw, and should not need disabling strict mode. With the default strict setting of enabled, the update will just silently fail.

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.

Mongoose 5.9.16

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions