Skip to content

Commit 5b71993

Browse files
authored
improve field deletion in collection (#6823)
* added filter to updateMany when deleting field * added test cases * added changelog entry
1 parent 9ba9620 commit 5b71993

File tree

3 files changed

+44
-1
lines changed

3 files changed

+44
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
### master
44
[Full Changelog](https://github.com/parse-community/parse-server/compare/4.3.0...master)
5+
- IMPROVE: Optimized deletion of class field from schema by using an index if available to do an index scan instead of a collection scan. [#6815](https://github.com/parse-community/parse-server/issues/6815). Thanks to [Manuel Trezza](https://github.com/mtrezza).
56

67
### 4.3.0
78
[Full Changelog](https://github.com/parse-community/parse-server/compare/4.2.0...4.3.0)

spec/MongoStorageAdapter.spec.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,43 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
351351
expect(postIndexPlan.executionStats.executionStages.stage).toBe('FETCH');
352352
});
353353

354+
it('should delete field without index', async () => {
355+
const database = Config.get(Parse.applicationId).database;
356+
const obj = new Parse.Object('MyObject');
357+
obj.set("test", 1);
358+
await obj.save();
359+
const schemaBeforeDeletion = await new Parse.Schema('MyObject').get();
360+
await database.adapter.deleteFields(
361+
"MyObject",
362+
schemaBeforeDeletion,
363+
["test"]
364+
);
365+
const schemaAfterDeletion = await new Parse.Schema('MyObject').get();
366+
expect(schemaBeforeDeletion.fields.test).toBeDefined();
367+
expect(schemaAfterDeletion.fields.test).toBeUndefined();
368+
});
369+
370+
it('should delete field with index', async () => {
371+
const database = Config.get(Parse.applicationId).database;
372+
const obj = new Parse.Object('MyObject');
373+
obj.set("test", 1);
374+
await obj.save();
375+
const schemaBeforeDeletion = await new Parse.Schema('MyObject').get();
376+
await database.adapter.ensureIndex(
377+
'MyObject',
378+
schemaBeforeDeletion,
379+
['test']
380+
);
381+
await database.adapter.deleteFields(
382+
"MyObject",
383+
schemaBeforeDeletion,
384+
["test"]
385+
);
386+
const schemaAfterDeletion = await new Parse.Schema('MyObject').get();
387+
expect(schemaBeforeDeletion.fields.test).toBeDefined();
388+
expect(schemaAfterDeletion.fields.test).toBeUndefined();
389+
});
390+
354391
if (
355392
semver.satisfies(process.env.MONGODB_VERSION, '>=4.0.4') &&
356393
process.env.MONGODB_TOPOLOGY === 'replicaset' &&

src/Adapters/Storage/Mongo/MongoStorageAdapter.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,14 +433,19 @@ export class MongoStorageAdapter implements StorageAdapter {
433433
collectionUpdate['$unset'][name] = null;
434434
});
435435

436+
const collectionFilter = { $or: [] };
437+
mongoFormatNames.forEach(name => {
438+
collectionFilter['$or'].push({ [name]: { $exists: true } });
439+
});
440+
436441
const schemaUpdate = { $unset: {} };
437442
fieldNames.forEach((name) => {
438443
schemaUpdate['$unset'][name] = null;
439444
schemaUpdate['$unset'][`_metadata.fields_options.${name}`] = null;
440445
});
441446

442447
return this._adaptiveCollection(className)
443-
.then((collection) => collection.updateMany({}, collectionUpdate))
448+
.then((collection) => collection.updateMany(collectionFilter, collectionUpdate))
444449
.then(() => this._schemaCollection())
445450
.then((schemaCollection) =>
446451
schemaCollection.updateSchema(className, schemaUpdate)

0 commit comments

Comments
 (0)