From cb0266035dd58c1fdd63bb7b0140f8c70d1fe458 Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Wed, 18 Feb 2026 13:06:27 +0100 Subject: [PATCH] [web] remove unnecessary filtering of rootFolder (#31585) 11 years ago, the db.projects collection was storing doc lines in the file-tree/rootFolder. Any operations on the project that did not need those lines were benefitting from excluding all those entries from the file-tree. These days, the verbose exclusions are not useful anymore and merely add load on mongo. REF: 9805c6a9ff852684ec276986d806e65c6844d1cb GitOrigin-RevId: 89f544688934c1ed1ca98877ffbe8baefe66c126 --- .../Features/Editor/EditorHttpController.mjs | 3 +- .../Features/Project/ProjectEntityHandler.mjs | 15 ++-- .../ProjectEntityMongoUpdateHandler.mjs | 6 +- .../src/Features/Project/ProjectGetter.mjs | 19 ----- .../Project/ProjectRootDocManager.mjs | 6 +- .../src/Editor/EditorHttpController.test.mjs | 4 +- .../Project/ProjectDetailsHandler.test.mjs | 1 - .../src/Project/ProjectEntityHandler.test.mjs | 10 +-- .../ProjectEntityMongoUpdateHandler.test.mjs | 2 +- .../ProjectEntityUpdateHandler.test.mjs | 1 - .../unit/src/Project/ProjectGetter.test.mjs | 81 ------------------- .../Project/ProjectRootDocManager.test.mjs | 14 ++-- 12 files changed, 29 insertions(+), 133 deletions(-) diff --git a/services/web/app/src/Features/Editor/EditorHttpController.mjs b/services/web/app/src/Features/Editor/EditorHttpController.mjs index 95eec08588..7dc8939186 100644 --- a/services/web/app/src/Features/Editor/EditorHttpController.mjs +++ b/services/web/app/src/Features/Editor/EditorHttpController.mjs @@ -77,8 +77,7 @@ async function joinProject(req, res, next) { } async function _buildJoinProjectView(req, projectId, userId) { - const project = - await ProjectGetter.promises.getProjectWithoutDocLines(projectId) + const project = await ProjectGetter.promises.getProject(projectId) if (project == null) { throw new Errors.NotFoundError('project not found') } diff --git a/services/web/app/src/Features/Project/ProjectEntityHandler.mjs b/services/web/app/src/Features/Project/ProjectEntityHandler.mjs index acc4e26438..70d79d533a 100644 --- a/services/web/app/src/Features/Project/ProjectEntityHandler.mjs +++ b/services/web/app/src/Features/Project/ProjectEntityHandler.mjs @@ -79,8 +79,9 @@ function getAllEntitiesFromProject(project) { } async function getAllDocPathsFromProjectById(projectId) { - const project = - await ProjectGetter.promises.getProjectWithoutDocLines(projectId) + const project = await ProjectGetter.promises.getProject(projectId, { + rootFolder: 1, + }) if (project == null) { throw new Errors.NotFoundError('no project') } @@ -120,8 +121,9 @@ async function getDoc(projectId, docId, options = {}) { * @param {ObjectId | string} docId */ async function getDocPathByProjectIdAndDocId(projectId, docId) { - const project = - await ProjectGetter.promises.getProjectWithoutDocLines(projectId) + const project = await ProjectGetter.promises.getProject(projectId, { + rootFolder: 1, + }) if (project == null) { throw new Errors.NotFoundError('no project') } @@ -165,8 +167,9 @@ async function getDocPathFromProjectByDocId(project, docId) { } async function _getAllFolders(projectId) { - const project = - await ProjectGetter.promises.getProjectWithoutDocLines(projectId) + const project = await ProjectGetter.promises.getProject(projectId, { + rootFolder: 1, + }) if (project == null) { throw new Errors.NotFoundError('no project') diff --git a/services/web/app/src/Features/Project/ProjectEntityMongoUpdateHandler.mjs b/services/web/app/src/Features/Project/ProjectEntityMongoUpdateHandler.mjs index 50d8d8f32d..c236e3be45 100644 --- a/services/web/app/src/Features/Project/ProjectEntityMongoUpdateHandler.mjs +++ b/services/web/app/src/Features/Project/ProjectEntityMongoUpdateHandler.mjs @@ -269,8 +269,10 @@ async function mkdirp(projectId, path, userId, options = {}) { // to make matching case-sensitive const folders = path.split('/').filter(folder => folder.length !== 0) - const project = - await ProjectGetter.promises.getProjectWithOnlyFolders(projectId) + const project = await ProjectGetter.promises.getProjectWithoutLock( + projectId, + { rootFolder: 1 } + ) if (path === '/') { return { newFolders: [], folder: project.rootFolder[0] } } diff --git a/services/web/app/src/Features/Project/ProjectGetter.mjs b/services/web/app/src/Features/Project/ProjectGetter.mjs index 9e2727a9cf..fc3eadfc44 100644 --- a/services/web/app/src/Features/Project/ProjectGetter.mjs +++ b/services/web/app/src/Features/Project/ProjectGetter.mjs @@ -11,25 +11,6 @@ import CollaboratorsGetter from '../Collaborators/CollaboratorsGetter.mjs' const { normalizeQuery } = Mongo const ProjectGetter = { - EXCLUDE_DEPTH: 8, - - async getProjectWithoutDocLines(projectId) { - const excludes = {} - for (let i = 1; i <= ProjectGetter.EXCLUDE_DEPTH; i++) { - excludes[`rootFolder${Array(i).join('.folders')}.docs.lines`] = 0 - } - return await ProjectGetter.getProject(projectId, excludes) - }, - - async getProjectWithOnlyFolders(projectId) { - const excludes = {} - for (let i = 1; i <= ProjectGetter.EXCLUDE_DEPTH; i++) { - excludes[`rootFolder${Array(i).join('.folders')}.docs`] = 0 - excludes[`rootFolder${Array(i).join('.folders')}.fileRefs`] = 0 - } - return await ProjectGetter.getProject(projectId, excludes) - }, - async getProject(projectId, projection = {}) { if (projectId == null) { throw new Error('no project id provided') diff --git a/services/web/app/src/Features/Project/ProjectRootDocManager.mjs b/services/web/app/src/Features/Project/ProjectRootDocManager.mjs index e955b21f92..8b4b212d87 100644 --- a/services/web/app/src/Features/Project/ProjectRootDocManager.mjs +++ b/services/web/app/src/Features/Project/ProjectRootDocManager.mjs @@ -146,8 +146,10 @@ async function ensureRootDocumentIsSet(projectId) { * @param {ObjectId | string} projectId */ async function ensureRootDocumentIsValid(projectId) { - const project = - await ProjectGetter.promises.getProjectWithoutDocLines(projectId) + const project = await ProjectGetter.promises.getProject(projectId, { + rootFolder: 1, + rootDoc_id: 1, + }) if (!project) { throw new Error('project not found') } diff --git a/services/web/test/unit/src/Editor/EditorHttpController.test.mjs b/services/web/test/unit/src/Editor/EditorHttpController.test.mjs index 2b883d4e93..adbff17239 100644 --- a/services/web/test/unit/src/Editor/EditorHttpController.test.mjs +++ b/services/web/test/unit/src/Editor/EditorHttpController.test.mjs @@ -131,7 +131,7 @@ describe('EditorHttpController', function () { } ctx.ProjectGetter = { promises: { - getProjectWithoutDocLines: sinon.stub().resolves(ctx.project), + getProject: sinon.stub().resolves(ctx.project), }, } ctx.ProjectEditorHandler = { @@ -461,7 +461,7 @@ describe('EditorHttpController', function () { describe('when project is not found', function () { beforeEach(async function (ctx) { - ctx.ProjectGetter.promises.getProjectWithoutDocLines.resolves(null) + ctx.ProjectGetter.promises.getProject.resolves(null) await new Promise(resolve => { ctx.next.callsFake(() => resolve()) ctx.EditorHttpController.joinProject(ctx.req, ctx.res, ctx.next) diff --git a/services/web/test/unit/src/Project/ProjectDetailsHandler.test.mjs b/services/web/test/unit/src/Project/ProjectDetailsHandler.test.mjs index 256f7f7c04..a7664c62e0 100644 --- a/services/web/test/unit/src/Project/ProjectDetailsHandler.test.mjs +++ b/services/web/test/unit/src/Project/ProjectDetailsHandler.test.mjs @@ -34,7 +34,6 @@ describe('ProjectDetailsHandler', function () { } ctx.ProjectGetter = { promises: { - getProjectWithoutDocLines: sinon.stub().resolves(ctx.project), getProject: sinon.stub().resolves(ctx.project), findAllUsersProjects: sinon.stub().resolves({ owned: [], diff --git a/services/web/test/unit/src/Project/ProjectEntityHandler.test.mjs b/services/web/test/unit/src/Project/ProjectEntityHandler.test.mjs index fe092d1ebd..a13130b1db 100644 --- a/services/web/test/unit/src/Project/ProjectEntityHandler.test.mjs +++ b/services/web/test/unit/src/Project/ProjectEntityHandler.test.mjs @@ -105,9 +105,7 @@ describe('ProjectEntityHandler', function () { ], }, ] - ctx.ProjectGetter.promises.getProjectWithoutDocLines = sinon - .stub() - .resolves(ctx.project) + ctx.ProjectGetter.promises.getProject = sinon.stub().resolves(ctx.project) }) describe('getAllDocs', function () { @@ -253,7 +251,7 @@ describe('ProjectEntityHandler', function () { }) it('should get the project without the docs lines', function (ctx) { - ctx.ProjectGetter.promises.getProjectWithoutDocLines + ctx.ProjectGetter.promises.getProject .calledWith(projectId) .should.equal(true) }) @@ -317,9 +315,7 @@ describe('ProjectEntityHandler', function () { ], }, ] - ctx.ProjectGetter.promises.getProjectWithoutDocLines = sinon - .stub() - .resolves(ctx.project) + ctx.ProjectGetter.promises.getProject = sinon.stub().resolves(ctx.project) }) describe('getAllDocs', function () { diff --git a/services/web/test/unit/src/Project/ProjectEntityMongoUpdateHandler.test.mjs b/services/web/test/unit/src/Project/ProjectEntityMongoUpdateHandler.test.mjs index ab400edc59..8c3e8c5600 100644 --- a/services/web/test/unit/src/Project/ProjectEntityMongoUpdateHandler.test.mjs +++ b/services/web/test/unit/src/Project/ProjectEntityMongoUpdateHandler.test.mjs @@ -185,7 +185,7 @@ describe('ProjectEntityMongoUpdateHandler', function () { .stub() .withArgs(ctx.project._id) .resolves(ctx.project), - getProjectWithOnlyFolders: sinon.stub().resolves(ctx.project), + getProject: sinon.stub().resolves(ctx.project), }, } diff --git a/services/web/test/unit/src/Project/ProjectEntityUpdateHandler.test.mjs b/services/web/test/unit/src/Project/ProjectEntityUpdateHandler.test.mjs index 386aa347a1..640d3ed569 100644 --- a/services/web/test/unit/src/Project/ProjectEntityUpdateHandler.test.mjs +++ b/services/web/test/unit/src/Project/ProjectEntityUpdateHandler.test.mjs @@ -109,7 +109,6 @@ describe('ProjectEntityUpdateHandler', function () { ctx.ProjectGetter = { promises: { getProject: sinon.stub(), - getProjectWithoutDocLines: sinon.stub(), }, } ctx.ProjectLocator = { diff --git a/services/web/test/unit/src/Project/ProjectGetter.test.mjs b/services/web/test/unit/src/Project/ProjectGetter.test.mjs index 676c4e0dda..b10d6a080b 100644 --- a/services/web/test/unit/src/Project/ProjectGetter.test.mjs +++ b/services/web/test/unit/src/Project/ProjectGetter.test.mjs @@ -89,87 +89,6 @@ describe('ProjectGetter', function () { ctx.ProjectGetter = (await import(modulePath)).default }) - describe('getProjectWithoutDocLines', function () { - beforeEach(function (ctx) { - ctx.ProjectGetter.promises.getProject = sinon.stub().resolves() - }) - - describe('passing an id', function () { - beforeEach(async function (ctx) { - await ctx.ProjectGetter.promises.getProjectWithoutDocLines( - ctx.project._id - ) - }) - - it('should call find with the project id', function (ctx) { - ctx.ProjectGetter.promises.getProject - .calledWith(ctx.project._id) - .should.equal(true) - }) - - it('should exclude the doc lines', function (ctx) { - const excludes = { - 'rootFolder.docs.lines': 0, - 'rootFolder.folders.docs.lines': 0, - 'rootFolder.folders.folders.docs.lines': 0, - 'rootFolder.folders.folders.folders.docs.lines': 0, - 'rootFolder.folders.folders.folders.folders.docs.lines': 0, - 'rootFolder.folders.folders.folders.folders.folders.docs.lines': 0, - 'rootFolder.folders.folders.folders.folders.folders.folders.docs.lines': 0, - 'rootFolder.folders.folders.folders.folders.folders.folders.folders.docs.lines': 0, - } - - ctx.ProjectGetter.promises.getProject - .calledWith(ctx.project._id, excludes) - .should.equal(true) - }) - }) - }) - - describe('getProjectWithOnlyFolders', function () { - beforeEach(function (ctx) { - ctx.ProjectGetter.promises.getProject = sinon.stub().resolves() - }) - - describe('passing an id', function () { - beforeEach(async function (ctx) { - await ctx.ProjectGetter.promises.getProjectWithOnlyFolders( - ctx.project._id - ) - }) - - it('should call find with the project id', function (ctx) { - ctx.ProjectGetter.promises.getProject - .calledWith(ctx.project._id) - .should.equal(true) - }) - - it('should exclude the docs and files lines', function (ctx) { - const excludes = { - 'rootFolder.docs': 0, - 'rootFolder.fileRefs': 0, - 'rootFolder.folders.docs': 0, - 'rootFolder.folders.fileRefs': 0, - 'rootFolder.folders.folders.docs': 0, - 'rootFolder.folders.folders.fileRefs': 0, - 'rootFolder.folders.folders.folders.docs': 0, - 'rootFolder.folders.folders.folders.fileRefs': 0, - 'rootFolder.folders.folders.folders.folders.docs': 0, - 'rootFolder.folders.folders.folders.folders.fileRefs': 0, - 'rootFolder.folders.folders.folders.folders.folders.docs': 0, - 'rootFolder.folders.folders.folders.folders.folders.fileRefs': 0, - 'rootFolder.folders.folders.folders.folders.folders.folders.docs': 0, - 'rootFolder.folders.folders.folders.folders.folders.folders.fileRefs': 0, - 'rootFolder.folders.folders.folders.folders.folders.folders.folders.docs': 0, - 'rootFolder.folders.folders.folders.folders.folders.folders.folders.fileRefs': 0, - } - ctx.ProjectGetter.promises.getProject - .calledWith(ctx.project._id, excludes) - .should.equal(true) - }) - }) - }) - describe('getProject', function () { describe('without projection', function () { describe('with project id', function () { diff --git a/services/web/test/unit/src/Project/ProjectRootDocManager.test.mjs b/services/web/test/unit/src/Project/ProjectRootDocManager.test.mjs index 48ae8394aa..00eec627ee 100644 --- a/services/web/test/unit/src/Project/ProjectRootDocManager.test.mjs +++ b/services/web/test/unit/src/Project/ProjectRootDocManager.test.mjs @@ -587,9 +587,7 @@ describe('ProjectRootDocManager', function () { beforeEach(function (ctx) { ctx.project = {} ctx.ProjectGetter.promises.getProject = sinon.stub().resolves(ctx.project) - ctx.ProjectGetter.promises.getProjectWithoutDocLines = sinon - .stub() - .resolves(ctx.project) + ctx.ProjectGetter.promises.getProject = sinon.stub().resolves(ctx.project) ctx.ProjectEntityUpdateHandler.promises.setRootDoc = sinon .stub() .resolves() @@ -614,7 +612,7 @@ describe('ProjectRootDocManager', function () { }) it('should find the project without doc lines', function (ctx) { - ctx.ProjectGetter.promises.getProjectWithoutDocLines + ctx.ProjectGetter.promises.getProject .calledWith(ctx.project_id) .should.equal(true) }) @@ -638,7 +636,7 @@ describe('ProjectRootDocManager', function () { }) it('should find the project without doc lines', function (ctx) { - ctx.ProjectGetter.promises.getProjectWithoutDocLines + ctx.ProjectGetter.promises.getProject .calledWith(ctx.project_id) .should.equal(true) }) @@ -665,7 +663,7 @@ describe('ProjectRootDocManager', function () { }) it('should find the project without doc lines', async function (ctx) { - ctx.ProjectGetter.promises.getProjectWithoutDocLines + ctx.ProjectGetter.promises.getProject .calledWith(ctx.project_id) .should.equal(true) }) @@ -679,9 +677,7 @@ describe('ProjectRootDocManager', function () { describe('when the project does not exist', function () { beforeEach(async function (ctx) { - ctx.ProjectGetter.promises.getProjectWithoutDocLines = sinon - .stub() - .resolves(null) + ctx.ProjectGetter.promises.getProject = sinon.stub().resolves(null) }) it('should reject', async function (ctx) {