Skip to content

Commit

Permalink
BREAKING CHANGE: make schema paths declared with `type: { name: Strin…
Browse files Browse the repository at this point in the history
…g }` create a single nested subdoc, remove `typePojoToMixed` because it is now always false

Fix #7181
  • Loading branch information
vkarpov15 committed Apr 26, 2020
1 parent 20953ae commit a51fbcc
Show file tree
Hide file tree
Showing 7 changed files with 17 additions and 58 deletions.
14 changes: 0 additions & 14 deletions docs/schematypes.pug
Original file line number Diff line number Diff line change
Expand Up @@ -395,20 +395,6 @@ block content
const Any = new Schema({ any: Object });
const Any = new Schema({ any: Schema.Types.Mixed });
const Any = new Schema({ any: mongoose.Mixed });
// Note that by default, if you're using `type`, putting _any_ POJO as the `type` will
// make the path mixed.
const Any = new Schema({
any: {
type: { foo: String }
} // "any" will be Mixed - everything inside is ignored.
});
// However, as of Mongoose 5.8.0, this behavior can be overridden with typePojoToMixed.
// In that case, it will create a single nested subdocument type instead.
const Any = new Schema({
any: {
type: { foo: String }
} // "any" will be a single nested subdocument.
}, {typePojoToMixed: false});
```

Since Mixed is a schema-less type, you can change the value to anything else you
Expand Down
6 changes: 1 addition & 5 deletions docs/subdocs.pug
Original file line number Diff line number Diff line change
Expand Up @@ -237,14 +237,10 @@ block content
reasons, this alternate declaration must be enabled via an option (either
on the parent schema instantiation or on the mongoose instance).
```javascript
var parentSchema = new Schema({
child: { type: { name: 'string' } }
}, { typePojoToMixed: false });
// Equivalent
var parentSchema = new Schema({
child: new Schema({ name: 'string' })
});
// Not equivalent! Careful - a Mixed path is created instead!
// Equivalent
var parentSchema = new Schema({
child: { type: { name: 'string' } }
});
Expand Down
1 change: 0 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ Mongoose.prototype.driver = require('./driver');
* - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()`
* - 'strict': true by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
* - 'selectPopulatedPaths': true by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
* - 'typePojoToMixed': true by default, may be `false` or `true`. Sets the default typePojoToMixed for schemas.
* - 'maxTimeMS': If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query
* - 'autoIndex': true by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance.
*
Expand Down
14 changes: 4 additions & 10 deletions lib/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ let id = 0;
* - [toJSON](/docs/guide.html#toJSON) - object - no default
* - [toObject](/docs/guide.html#toObject) - object - no default
* - [typeKey](/docs/guide.html#typeKey) - string - defaults to 'type'
* - [typePojoToMixed](/docs/guide.html#typePojoToMixed) - boolean - defaults to true. Determines whether a type set to a POJO becomes a Mixed path or a Subdocument
* - [useNestedStrict](/docs/guide.html#useNestedStrict) - boolean - defaults to false
* - [validateBeforeSave](/docs/guide.html#validateBeforeSave) - bool - defaults to `true`
* - [versionKey](/docs/guide.html#versionKey): string - defaults to "__v"
Expand Down Expand Up @@ -414,8 +413,7 @@ Schema.prototype.defaultOptions = function(options) {
_id: true,
noVirtualId: false, // deprecated, use { id: false }
id: true,
typeKey: 'type',
typePojoToMixed: 'typePojoToMixed' in baseOptions ? baseOptions.typePojoToMixed : true
typeKey: 'type'
}, utils.clone(options));

if (options.read) {
Expand Down Expand Up @@ -501,14 +499,13 @@ Schema.prototype.add = function add(obj, prefix) {
this.add(obj[key], fullPath + '.');
} else {
// There IS a bona-fide type key that may also be a POJO
if (!this.options.typePojoToMixed && utils.isPOJO(obj[key][this.options.typeKey])) {
const _typeDef = obj[key][this.options.typeKey];
if (utils.isPOJO(_typeDef) && Object.keys(_typeDef).length > 0) {
// If a POJO is the value of a type key, make it a subdocument
if (prefix) {
this.nested[prefix.substr(0, prefix.length - 1)] = true;
}
// Propage `typePojoToMixed` to implicitly created schemas
const opts = { typePojoToMixed: false };
const _schema = new Schema(obj[key][this.options.typeKey], opts);
const _schema = new Schema(_typeDef);
const schemaWrappedPath = Object.assign({}, obj[key], { type: _schema });
this.path(prefix + key, schemaWrappedPath);
} else {
Expand Down Expand Up @@ -929,9 +926,6 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
if (options.hasOwnProperty('strict')) {
childSchemaOptions.strict = options.strict;
}
if (options.hasOwnProperty('typePojoToMixed')) {
childSchemaOptions.typePojoToMixed = options.typePojoToMixed;
}
const childSchema = new Schema(cast, childSchemaOptions);
childSchema.$implicitlyCreated = true;
return new MongooseTypes.DocumentArray(path, childSchema, obj);
Expand Down
3 changes: 1 addition & 2 deletions lib/validoptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ const VALID_OPTIONS = Object.freeze([
'useFindAndModify',
'useNewUrlParser',
'usePushEach',
'useUnifiedTopology',
'typePojoToMixed'
'useUnifiedTopology'
]);

module.exports = VALID_OPTIONS;
7 changes: 7 additions & 0 deletions test/model.indexes.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,13 @@ describe('model', function() {
});

describe('global autoIndexes (gh-1875)', function() {
beforeEach(() => {
const Test = db.model('Test', Schema({}));
return Test.collection.dropIndexes();
});

beforeEach(() => db.deleteModel(/Test/));

it('will create indexes as a default', function(done) {
const schema = new Schema({ name: { type: String, index: true } });
const Test = db.model('Test', schema);
Expand Down
30 changes: 4 additions & 26 deletions test/types.embeddeddocumentdeclarative.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,8 @@ describe('types.embeddeddocumentdeclarative', function() {
}
};

describe('with the default legacy behavior (typePojoToMixed=true)', function() {
describe('creates subdocument schema if `type` is an object with keys', function() {
const ParentSchema = new mongoose.Schema(ParentSchemaDef);
it('interprets the POJO as Mixed (gh-7494)', function(done) {
assert.equal(ParentSchema.paths.child.instance, 'Mixed');
done();
});
it('does not enforce provided schema on the child path (gh-7494)', function(done) {
const ParentModel = mongoose.model('ParentModel-7494-EmbeddedDeclarativeMixed', ParentSchema);
const swampGuide = new ParentModel({
name: 'Swamp Guide',
child: {
name: 'Tingle',
mixedUp: 'very'
}
});
const tingle = swampGuide.toObject().child;

assert.equal(tingle.name, 'Tingle');
assert.equal(tingle.mixedUp, 'very');
done();
});
});
describe('with the optional subschema behavior (typePojoToMixed=false)', function() {
const ParentSchema = new mongoose.Schema(ParentSchemaDef, { typePojoToMixed: false });
it('interprets the POJO as a subschema (gh-7494)', function(done) {
assert.equal(ParentSchema.paths.child.instance, 'Embedded');
assert.strictEqual(ParentSchema.paths.child['$isSingleNested'], true);
Expand Down Expand Up @@ -77,7 +55,7 @@ describe('types.embeddeddocumentdeclarative', function() {
type: { test: String }
}
}]
}, { typePojoToMixed: false });
});

assert.ok(schema.path('arr').schema.path('nested').instance !== 'Mixed');
assert.ok(schema.path('arr').schema.path('nested.test') instanceof mongoose.Schema.Types.String);
Expand All @@ -94,7 +72,7 @@ describe('types.embeddeddocumentdeclarative', function() {
}
}
}
}, { typePojoToMixed: false });
});

assert.ok(schema.path('l1').instance !== 'Mixed');
assert.ok(schema.path('l1.l2').instance !== 'Mixed');
Expand All @@ -112,7 +90,7 @@ describe('types.embeddeddocumentdeclarative', function() {
}
};
const ParentSchemaNotMixed = new Schema(ParentSchemaDef);
const ParentSchemaNotSubdoc = new Schema(ParentSchemaDef, { typePojoToMixed: false });
const ParentSchemaNotSubdoc = new Schema(ParentSchemaDef);
it('does not create a path for child in either option', function(done) {
assert.equal(ParentSchemaNotMixed.paths['child.name'].instance, 'String');
assert.equal(ParentSchemaNotSubdoc.paths['child.name'].instance, 'String');
Expand Down

0 comments on commit a51fbcc

Please sign in to comment.