Eliminate redundant project DB fetches across route handlers#478
Merged
thehabes merged 10 commits intodevelopmentfrom Mar 16, 2026
Merged
Eliminate redundant project DB fetches across route handlers#478thehabes merged 10 commits intodevelopmentfrom
thehabes merged 10 commits intodevelopmentfrom
Conversation
Co-authored-by: thehabes <[email protected]>
- Add optional `project` param to `findPageById()` and `findLayerById()` in shared.js so callers with a pre-loaded project can skip the redundant DB fetch - Pass pre-loaded `project` to `findLayerById()` and `findPageById()` in layer/index.js - Pass pre-loaded `project` to `findPageById()` in page/index.js PUT /:pageId - Pass pre-loaded `project` to `findPageById()` in line/index.js (POST, PUT, PATCH×2) - Use `project.data` directly in customMetadataRouter.js GET/POST/PUT /:id/custom instead of calling `database.findOne()` again after `checkUserAccess()` already loaded it - Restructure projectReadRouter.js GET /:id to call `loadAsUser()` once and derive the access check from its result via new `userHasAccess()` helper (saves project+group load) - Remove redundant `loadAsUser()` call in projectReadRouter.js GET /:id/manifest; use `project.data` from `checkUserAccess()` for the existence check instead - Add optional `preloadedProjectData` param to `ProjectFactory.exportManifest()` so callers with already-loaded data skip the internal `loadAsUser()` fetch Co-authored-by: thehabes <[email protected]>
…mment on loadAsUser error pattern Co-authored-by: thehabes <[email protected]>
Copilot
AI
changed the title
[WIP] Fix redundant project data query in utility functions
Eliminate redundant project DB fetches across route handlers
Mar 16, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This PR reduces redundant project database reads by allowing route handlers and manifest export logic to reuse project data that was already loaded during access checks, rather than fetching the same project again inside shared utilities and factory methods.
Changes:
- Add optional
projectparameter tofindPageById()/findLayerById()to reuse pre-loadedProjectinstances. - Update multiple layer/page/line route handlers to pass the pre-loaded
projectinto these utilities. - Avoid redundant project loads in project read/manifest/custom-metadata routes by reusing
project.dataand by extendingProjectFactory.exportManifest()to accept preloaded project data.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| utilities/shared.js | Allow page/layer lookup helpers to reuse already-loaded project data. |
| layer/index.js | Pass preloaded project into layer/page lookup utilities during updates. |
| page/index.js | Pass preloaded project into findPageById() on update. |
| line/index.js | Pass preloaded project into findPageById() across create/update/patch routes. |
| project/customMetadataRouter.js | Reuse project.data instead of a second direct DB fetch. |
| project/projectReadRouter.js | Use loadAsUser() once and perform access checking from the returned data to avoid double fetch. |
| classes/Project/ProjectFactory.js | Let exportManifest() accept preloaded project data to avoid an internal loadAsUser() query. |
You can also share your feedback on Copilot code review. Take the survey.
Comment on lines
+111
to
+114
| return userRoleNames.some(role => { | ||
| const perms = rolePermissions[role] | ||
| if (!perms || !Array.isArray(perms)) return false | ||
| return perms.some(perm => { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Route handlers were loading project data twice per request: once via
checkUserAccess()(which internally calls#load()), and again inside utility functions likefindLayerById(),findPageById(), andProjectFactory.loadAsUser().Changes
utilities/shared.jsfindPageById(pageId, projectId, project = null)— accepts optional pre-loadedProject; skipsProject.getById()when providedfindLayerById(layerId, projectId, project = null)— same patternRoute handlers — pass pre-loaded
projectto utilitieslayer/index.jsPUT /:layerId→findLayerById()+findPageById()page/index.jsPUT /:pageId→findPageById()line/index.jsPOST /,PUT /:lineId,PATCH /:lineId/text,PATCH /:lineId/bounds→findPageById()project/customMetadataRouter.js— GET/POST/PUT/:id/customdatabase.findOne({ _id: id }, "projects")withproject.dataalready populated bycheckUserAccess()project/projectReadRouter.jsGET /:id— callsProjectFactory.loadAsUser()once (the aggregation that fetches project + group + collaborators) and derives the access check from its result via a new localuserHasAccess()helper, replacing the separatecheckUserAccess()+loadAsUser()pairGET /:id/manifest— removes the standaloneloadAsUser()existence-check call; usesproject.datafromcheckUserAccess()and passes it toexportManifest()classes/Project/ProjectFactory.jsexportManifest(projectId, preloadedProjectData = null)— skips internalloadAsUser()when project data is already availableOriginal prompt
🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.