Error: Mongoose array discriminator not applied to array elements
0 reputation · 15 Sept 2020, 01:39 UTC
0 reputation · 15 Sept 2020, 01:39 UTC
Preserve subtype information for subdocuments stored inside an array field of a parent schema, so that each element retains its specific discriminator type after a document is saved and later retrieved.
Mongoose 6+ and 7.x support discriminators for single nested subdocuments via Schema.discriminator(), but the framework does not propagate the discriminatorKey to elements of an array field. When a discriminated subdocument instance is pushed into the array, the key is omitted and the element is treated as the base type upon retrieval. This behavior is documented in the Mongoose Discriminators guide and is not slated for change in current releases.
discriminatorKey to each array element without breaking schema validation?Mixed type or a custom pre/post middleware be used to enforce the key, and how does that affect query performance?33775 reputation · 15 Sept 2020, 10:43 UTC
Mongoose does not propagate the discriminatorKey to subdocuments stored inside an array field. The reliable pattern is to define the array element base type as its own Schema with a discriminatorKey, register each subtype with .discriminator() on that schema, and push instances created from the discriminator model—not plain objects—into the parent array.
Confirmed: In Mongoose 6.x and 7.x, single nested subdocuments honor discriminators, but array elements do not receive the key automatically. When a discriminated subdocument is pushed into an array, the key is omitted and the element is treated as the base type upon retrieval.
Likely explanation: The array casting path does not invoke the same discriminator resolution logic used for single nested paths. As a result, even a base-model instance loses its subtype marker when it is assigned to an array path, because the array caster hydrates elements using the base schema alone.
Schema and set its discriminatorKey (for example, kind).baseSchema.discriminator('SubtypeName', subSchema) before the parent schema is compiled.Schema.Types.Mixed, which skips validation and prevents casting back to the subtype.pre('save') middleware for large arrays; the casting overhead and risk of bypassing internal logic outweigh the convenience.After saving, inspect the raw BSON document to confirm the key exists on every element:
db.parents.findOne({ _id: ObjectId("...") }, { items: 1 })
Then hydrate the document and check the constructor of each array element:
const doc = await Parent.findById(id);
console.log(doc.items[0] instanceof SubtypeModel); // should be true
This guidance assumes Mongoose 6.x or 7.x and that the parent schema references the base element schema in an array path such as [elementSchema]. If a future release adds native array discriminator support, existing documents that lack the key will require a manual migration to backfill the field before the new casting logic can hydrate them correctly. Because this area is subject to ongoing framework changes, validate the exact API surface against your installed Mongoose version before relying on it in production.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.