Skip to content

Commit 642abd1

Browse files
authored
Merge pull request #13953 from Automattic/vkarpov15/gh-13874
Avoid storing a separate entry in schema `subpaths` for every element in an array
2 parents 660ea80 + 82f2ca8 commit 642abd1

File tree

2 files changed

+42
-7
lines changed

2 files changed

+42
-7
lines changed

lib/schema.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ const isPOJO = utils.isPOJO;
3737

3838
let id = 0;
3939

40+
const numberRE = /^\d+$/;
41+
4042
/**
4143
* Schema constructor.
4244
*
@@ -1004,7 +1006,7 @@ Schema.prototype.path = function(path, obj) {
10041006

10051007
// subpaths?
10061008
return /\.\d+\.?.*$/.test(path)
1007-
? getPositionalPath(this, path)
1009+
? getPositionalPath(this, path, cleanPath)
10081010
: undefined;
10091011
}
10101012

@@ -1621,7 +1623,7 @@ Schema.prototype.pathType = function(path) {
16211623
}
16221624

16231625
if (/\.\d+\.|\.\d+$/.test(path)) {
1624-
return getPositionalPathType(this, path);
1626+
return getPositionalPathType(this, path, cleanPath);
16251627
}
16261628
return 'adhocOrUndefined';
16271629
};
@@ -1665,7 +1667,7 @@ Schema.prototype.setupTimestamp = function(timestamps) {
16651667
* @api private
16661668
*/
16671669

1668-
function getPositionalPathType(self, path) {
1670+
function getPositionalPathType(self, path, cleanPath) {
16691671
const subpaths = path.split(/\.(\d+)\.|\.(\d+)$/).filter(Boolean);
16701672
if (subpaths.length < 2) {
16711673
return self.paths.hasOwnProperty(subpaths[0]) ?
@@ -1716,7 +1718,7 @@ function getPositionalPathType(self, path) {
17161718
val = val.schema.path(subpath);
17171719
}
17181720

1719-
self.subpaths[path] = val;
1721+
self.subpaths[cleanPath] = val;
17201722
if (val) {
17211723
return 'real';
17221724
}
@@ -1731,9 +1733,9 @@ function getPositionalPathType(self, path) {
17311733
* ignore
17321734
*/
17331735

1734-
function getPositionalPath(self, path) {
1735-
getPositionalPathType(self, path);
1736-
return self.subpaths[path];
1736+
function getPositionalPath(self, path, cleanPath) {
1737+
getPositionalPathType(self, path, cleanPath);
1738+
return self.subpaths[cleanPath];
17371739
}
17381740

17391741
/**
@@ -2625,6 +2627,9 @@ Schema.prototype._getSchema = function(path) {
26252627
// Re: gh-5628, because `schema.path()` doesn't take $ into account.
26262628
parts[i] = '0';
26272629
}
2630+
if (numberRE.test(parts[i])) {
2631+
parts[i] = '$';
2632+
}
26282633
}
26292634
return search(parts, _this);
26302635
};

test/document.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12521,6 +12521,36 @@ describe('document', function() {
1252112521
assert.strictEqual(attachmentSchemaPreValidateCalls, 1);
1252212522
});
1252312523

12524+
it('avoids creating separate subpaths entry for every element in array (gh-13874)', async function() {
12525+
const tradeSchema = new mongoose.Schema({ tradeId: Number, content: String });
12526+
12527+
const testSchema = new mongoose.Schema(
12528+
{
12529+
userId: Number,
12530+
tradeMap: {
12531+
type: Map,
12532+
of: tradeSchema
12533+
}
12534+
}
12535+
);
12536+
12537+
const TestModel = db.model('Test', testSchema);
12538+
12539+
12540+
const userId = 100;
12541+
const user = await TestModel.create({ userId, tradeMap: new Map() });
12542+
12543+
// add subDoc
12544+
for (let id = 1; id <= 10; id++) {
12545+
const trade = { tradeId: id, content: 'test' };
12546+
user.tradeMap.set(trade.tradeId.toString(), trade);
12547+
}
12548+
await user.save();
12549+
await TestModel.deleteOne({ userId });
12550+
12551+
assert.equal(Object.keys(TestModel.schema.subpaths).length, 3);
12552+
});
12553+
1252412554
it('handles embedded discriminators defined using Schema.prototype.discriminator (gh-13898)', async function() {
1252512555
const baseNestedDiscriminated = new Schema({
1252612556
type: { type: Number, required: true }

0 commit comments

Comments
 (0)