Skip to content

Comments

fix: correct mention total count calculation (#38908)#38912

Open
Amanjha112113 wants to merge 1 commit intoRocketChat:developfrom
Amanjha112113:fix-38908-mention-count
Open

fix: correct mention total count calculation (#38908)#38912
Amanjha112113 wants to merge 1 commit intoRocketChat:developfrom
Amanjha112113:fix-38908-mention-count

Conversation

@Amanjha112113
Copy link

@Amanjha112113 Amanjha112113 commented Feb 22, 2026

Proposed changes

Fixes #38908

This PR corrects a critical performance regression in the channels.getAllUserMentionsByChannel endpoint.
Previously, the endpoint used getUserMentionsByChannel twice - once for the requested paginated chunk and once without skip/limit to compute the .length of the entire document set.

This has been refactored to use Messages.findPaginatedVisibleByMentionAndRoomId. This allows us to concurrently resolve the paginated cursor and optimally fetch the total document count strictly from the database via Promise.all([cursor.toArray(), totalCount]).

This eliminates massive O(n) memory allocation and server latency when querying channels with thousands of mentions.

Issue(s)

Closes #38908

Steps to test or reproduce

  1. Create a public channel.
  2. Accumulate thousands of user mentions inside the channel.
  3. Call GET /api/v1/channels.getAllUserMentionsByChannel?roomId=<id>&count=25&offset=0.
  4. Observe memory usage and database queries drastically reduced. Response will be instant for large amounts of mentions.

Summary by CodeRabbit

  • Bug Fixes

    • Improved access control validation for channel mentions, ensuring users can only access mentions they are authorized to view.
  • Refactor

    • Enhanced pagination mechanism for channel mention retrieval to improve performance and scalability.

@Amanjha112113 Amanjha112113 requested a review from a team as a code owner February 22, 2026 19:42
@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Feb 22, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Feb 22, 2026

⚠️ No Changeset found

Latest commit: 55bfdde

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@CLAassistant
Copy link

CLAassistant commented Feb 22, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 22, 2026

Walkthrough

The change refactors the channels.getAllUserMentionsByChannel endpoint to resolve a performance regression. Previously, the endpoint called getUserMentionsByChannel twice per request—once for paginated results and again without pagination to compute total count. The new implementation uses a single paginated query method that returns both data and total count efficiently.

Changes

Cohort / File(s) Summary
API Endpoint Optimization
apps/meteor/app/api/server/v1/channels.ts
Replaced dual getUserMentionsByChannel calls with Messages.findPaginatedVisibleByMentionAndRoomId to eliminate redundant full-dataset fetches. Added user validation (username check), access control verification via canAccessRoomAsync, and channel resolution via findChannelByIdOrName. Returns paginated mentions with computed totalCount in single database query.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit saw duplication's blight,
Two queries where one would suffice and right,
We hopped through the code with careful pace,
Removed the redundant fetch embrace,
Now mentions flow swift—efficient, lean and light! 🚀

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix: correct mention total count calculation' directly aligns with the main objective of fixing the total mention count computation in the channels.getAllUserMentionsByChannel endpoint.
Linked Issues check ✅ Passed The PR successfully addresses all coding objectives from issue #38908: replaces the inefficient dual getUserMentionsByChannel calls with Messages.findPaginatedVisibleByMentionAndRoomId, adds proper access checks, and computes total count via database countDocuments pattern rather than loading all documents into memory.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the mention total count calculation issue; the refactored endpoint logic, access control validation, and parameter type formatting are all necessary to implement the fix without introducing unrelated modifications.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/meteor/app/api/server/v1/channels.ts (1)

439-446: Avoid the extra Users.findOneById round-trip — use this.user directly.

Since the route is authRequired: true, this.user is already populated by the auth middleware and carries the username field. Fetching the full document again just to read username adds an unnecessary DB query on every mention request.

♻️ Proposed refactor
-			const user = await Users.findOneById(this.userId);
-			if (!user?.username) {
+			if (!this.user?.username) {
 				return API.v1.failure('Invalid user');
 			}
 
 			if (!(await canAccessRoomAsync(findResult, { _id: this.userId }))) {
 				return API.v1.forbidden();
 			}
 
 			const { cursor, totalCount } = Messages.findPaginatedVisibleByMentionAndRoomId(
-				user.username,
+				this.user.username,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/app/api/server/v1/channels.ts` around lines 439 - 446, Replace
the extra DB lookup Users.findOneById with the request-authenticated user object
(this.user): check this.user?.username instead of awaiting
Users.findOneById(this.userId) and keep the existing authorization call
canAccessRoomAsync(findResult, { _id: this.userId }) as-is; this removes the
unnecessary round-trip while preserving the username check and room access
logic.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dad0dba and 55bfdde.

📒 Files selected for processing (1)
  • apps/meteor/app/api/server/v1/channels.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/app/api/server/v1/channels.ts
🧠 Learnings (4)
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.

Applied to files:

  • apps/meteor/app/api/server/v1/channels.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/app/api/server/v1/channels.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/app/api/server/v1/channels.ts
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • apps/meteor/app/api/server/v1/channels.ts
🧬 Code graph analysis (1)
apps/meteor/app/api/server/v1/channels.ts (2)
packages/models/src/index.ts (1)
  • Users (192-192)
apps/meteor/app/authorization/server/index.ts (1)
  • canAccessRoomAsync (10-10)
🔇 Additional comments (2)
apps/meteor/app/api/server/v1/channels.ts (2)

66-71: LGTM — formatting-only change, no behavioral impact.


448-465: Normalization concern is not applicable — old implementation also returns raw documents.

The old getUserMentionsByChannel method (apps/meteor/app/mentions/server/methods/getUserMentionsByChannel.ts:36) returns Messages.findVisibleByMentionAndRoomId(user.username, roomId, options).toArray() without calling normalizeMessagesForUser. The new endpoint maintains identical behavior. While other message-returning endpoints like channels.messages and channels.anonymousread do normalize, the mentions endpoint never did, so this is not a regression.

Likely an incorrect or invalid review comment.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/meteor/app/api/server/v1/channels.ts`:
- Around line 439-446: Replace the extra DB lookup Users.findOneById with the
request-authenticated user object (this.user): check this.user?.username instead
of awaiting Users.findOneById(this.userId) and keep the existing authorization
call canAccessRoomAsync(findResult, { _id: this.userId }) as-is; this removes
the unnecessary round-trip while preserving the username check and room access
logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

channels.getAllUserMentionsByChannel fetches all mentions into memory to compute total count performance regression

2 participants