Summary
Under Mongoose 9, composeMongoose types scalar arrays nested inside a plain (non-subdocument) object as the JSON scalar instead of a typed GraphQL list (e.g. [Float]). Top-level scalar arrays and arrays of subdocuments are unaffected. The same models produce correctly-typed lists under Mongoose 8, so this is specific to the Mongoose 9 .caster removal.
I searched the open/closed issues and didn't find an existing report — apologies if I missed one.
Minimal reproduction
const mongoose = require('mongoose');
const { composeMongoose } = require('graphql-compose-mongoose');
const { schemaComposer } = require('graphql-compose');
const schema = new mongoose.Schema({
location: { type: { type: String, default: 'Point' }, coordinates: [Number] }, // scalar array nested in a plain object
score: { sets: [[{ type: Number }]], comments: [String] },
topLevelArr: [Number], // control: top-level scalar array
});
const TC = composeMongoose(mongoose.model('Probe', schema), { schemaComposer });
console.log(TC.toSDL({ deep: true, exclude: ['MongoID'] }));
Expected (Mongoose 8)
type Probe { topLevelArr: [Float] }
type ProbeLocation { coordinates: [Float] }
type ProbeScore { sets: [[Float]] comments: [String] }
Actual (Mongoose 9)
type Probe { topLevelArr: [Float] } # top-level array: still correct
type ProbeLocation { coordinates: JSON } # nested-in-object array: wrong
type ProbeScore { sets: JSON comments: JSON }
The control (topLevelArr) shows it's specifically the nested-in-an-object case that breaks.
Root cause
In src/fieldsConverter.ts (_getFieldComplexType), the array branch only recognizes .caster:
} else if (field instanceof mongoose.Schema.Types.Array || field?.caster?.instance) {
return ComplexTypes.ARRAY;
}
Mongoose 9 removed SchemaType.caster in favor of embeddedSchemaType. For an array unwrapped out of a plain object, the instanceof check doesn't fire and field.caster is undefined, so it falls through to SCALAR and scalarToGraphQL emits the JSON fallback.
arrayToGraphQL was already updated for this (field.caster || field.embeddedSchemaType), but the classifier above wasn't — so it never reaches arrayToGraphQL.
Suggested fix
Add the embeddedSchemaType fallback to the classifier:
} else if (
field instanceof mongoose.Schema.Types.Array ||
field?.caster?.instance ||
field?.embeddedSchemaType?.instance
) {
return ComplexTypes.ARRAY;
}
This keeps Mongoose 8 working (via .caster) and fixes Mongoose 9 (via .embeddedSchemaType); it only matches array fields, so other field types are unaffected.
Summary
Under Mongoose 9,
composeMongoosetypes scalar arrays nested inside a plain (non-subdocument) object as theJSONscalar instead of a typed GraphQL list (e.g.[Float]). Top-level scalar arrays and arrays of subdocuments are unaffected. The same models produce correctly-typed lists under Mongoose 8, so this is specific to the Mongoose 9.casterremoval.I searched the open/closed issues and didn't find an existing report — apologies if I missed one.
Minimal reproduction
Expected (Mongoose 8)
Actual (Mongoose 9)
The control (
topLevelArr) shows it's specifically the nested-in-an-object case that breaks.Root cause
In
src/fieldsConverter.ts(_getFieldComplexType), the array branch only recognizes.caster:Mongoose 9 removed
SchemaType.casterin favor ofembeddedSchemaType. For an array unwrapped out of a plain object, theinstanceofcheck doesn't fire andfield.casterisundefined, so it falls through toSCALARandscalarToGraphQLemits theJSONfallback.arrayToGraphQLwas already updated for this (field.caster || field.embeddedSchemaType), but the classifier above wasn't — so it never reachesarrayToGraphQL.Suggested fix
Add the
embeddedSchemaTypefallback to the classifier:This keeps Mongoose 8 working (via
.caster) and fixes Mongoose 9 (via.embeddedSchemaType); it only matches array fields, so other field types are unaffected.