Skip to content

Missing .lean() on read-only Mongoose queries #1934

Description

@david-rocca

Summary

Several read-only Mongoose query paths still hydrate full documents even though the code only reads fields, serializes data, or builds response objects. Adding .lean() would reduce Mongoose hydration CPU/memory overhead and likely improve endpoint latency. This will not make MongoDB execute the query itself faster; it reduces Node/Mongoose post-query work.

High-confidence candidates

Area Location Why it is safe Suggested fix
CVE record lookup src/repositories/cveRepository.js:9 Callers read result.cve, check existence, clone, or build a new Cve model before writing. No caller saves the returned document. Add .lean() to this.collection.findOne().byCveId(id).
CVE-ID lookup src/repositories/cveIdRepository.js:9 Callers read state/owner/date fields or clone to plain JSON before findOneAndUpdate. No caller saves the returned document. Add .lean() to this.collection.findOne().byCveId(id).
Non-sequential CVE-ID available pool src/controller/cve-id.controller/cve-id.controller.js:696, :710, :736, :752 via BaseRepository.find The available IDs are only read by available[index].cve_id and removed from the local array with splice. No document methods are used. Allow BaseRepository.find to combine lean and limit, then call with { limit: availableLimit, lean: true }. Current branching in src/repositories/baseRepository.js:43 makes lean and limit mutually exclusive.
Registry org detail response src/repositories/baseOrgRepository.js:536 getOrg immediately calls data.toObject() and then only normalizes, enriches, filters, and returns response data. Related org lookups in the same method already use .lean(). Pass { ...options, lean: true } only inside getOrg, then remove the toObject() dependency. Do not make findOneByShortName/findOneByUUID lean by default because update flows save those docs.
Conversation list by target src/repositories/conversationRepository.js:51 Results are immediately converted with toObject(), filtered/redacted, and returned. Create/edit paths use separate hydrated queries for save(). Add .lean() to the ConversationModel.find(...) query and remove toObject().
Conversation lookup by index src/repositories/conversationRepository.js:73 Used to get the conversation UUID/author for authorization before editConversation refetches the document for saving. Add .lean() to the indexed find(...).skip(...).limit(1) query.
Review object read-with-conversation helpers src/repositories/reviewObjectRepository.js:39, :96, :126 Each helper converts the review object to plain data, attaches conversations, filters new_review_data, and returns it. Update/approve/reject helpers are separate and still need hydrated docs. Add .lean() to those ReviewObjectModel.findOne(...) queries and remove toObject().
User/org map expansion helpers src/repositories/baseUserRepository.js:207, src/repositories/baseOrgRepository.js:251 These are used by registry org _userMap building. Callers already tolerate plain objects with asPlainObject. Add .lean() to both projected find(...) queries.
Boolean/existence helpers src/repositories/baseOrgRepository.js:311, :332, :1211, :1240; src/repositories/baseUserRepository.js:89, :109, :328 These only return booleans, collision strings, role checks, or UUID arrays. Add projected .lean() or use exists() where only existence is needed.
Legacy CVE-ID map preload src/repositories/orgRepository.js:50, src/repositories/userRepository.js:64 used by src/controller/cve-id.controller/cve-id.controller.js:40 The CVE-ID list endpoint only builds maps from UUID, short name, username, and org UUID. Add .select(...) plus .lean() in these repository methods or add dedicated map-loading methods.
Audit reads src/repositories/auditRepository.js:89, :98, :106, :114 These return audit data directly or sort/slice history arrays. No save occurs on returned documents. Add .lean() and remove toObject() in findAllAuditDocuments.
Glossary reads src/repositories/glossaryRepository.js:9, :13 Controllers return JSON directly or use existence checks. No document methods are needed. Add .lean() before .exec().

Not safe to change globally

Do not default these shared methods to lean without call-site options: BaseOrgRepository.findOneByShortName, BaseOrgRepository.findOneByUUID, BaseUserRepository.findUserByUUID, BaseUserRepository.findOneByUsernameAndOrgShortname, and legacy UserRepository.findOneByUUID. Some update flows mutate returned docs and call .save(), .overwrite(), .pull(), or .addToSet().

Suggested tests

Run targeted unit/integration coverage for CVE, CVE-ID reservation, registry org detail, registry user/org expansion, conversation, review object, audit, and glossary endpoints after implementation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Needs Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions