Skip to content

fix(mongo-orm): .select() combined with .include() drops joined relation fields via $project stage - #30170

Open
rajat12826 wants to merge 1 commit into
prisma:mainfrom
rajat12826:fix/mongo-orm-select-include-projection
Open

fix(mongo-orm): .select() combined with .include() drops joined relation fields via $project stage#30170
rajat12826 wants to merge 1 commit into
prisma:mainfrom
rajat12826:fix/mongo-orm-select-include-projection

Conversation

@rajat12826

@rajat12826 rajat12826 commented Aug 30, 2026

Copy link
Copy Markdown

Fix MongoDB $project Dropping Included Relations

PR Description

Fixes #30169

Problem

When chaining .select() and .include() in a MongoDB ORM query, the query compiler emits a $lookup stage to join the related collection but then builds a $project stage containing only the selected scalar fields.

In MongoDB aggregation pipelines, an inclusion projection such as:

{ name: 1, _id: 0 }

drops all fields that are not explicitly listed. As a result, the relation field produced by $lookup is silently discarded at runtime, even though TypeScript infers it as present.

Example

const results = await db.user
  .select('name')
  .include('posts')
  .all();

// Expected:
// { name: "Alice", posts: [...] }

// Actual:
// { name: "Alice" } ← posts dropped by $project

Fix

In compileMongoQuery, when building the $project projection object, iterate over state.includes and add each inc.relationName to the projection alongside the selected scalar fields.

Before

if (state.selectedFields && state.selectedFields.length > 0) {
const projection: Record<string, 0 | 1> = {};

for (const field of state.selectedFields) {
projection[field] = 1;
}

if (!Object.hasOwn(projection, '_id')) {
projection['_id'] = 0;
}

stages.push(new MongoProjectStage(projection));
}

After

if (state.selectedFields && state.selectedFields.length > 0) {
const projection: Record<string, 0 | 1> = {};

for (const field of state.selectedFields) {
projection[field] = 1;
}

  • for (const inc of state.includes) {
  • projection[inc.relationName] = 1;
  • }

if (!Object.hasOwn(projection, '_id')) {
projection['_id'] = 0;
}

stages.push(new MongoProjectStage(projection));
}

This ensures that relation aliases generated by $lookup are preserved by the subsequent $project stage.

Tests Added

Three new test cases were added to compile.test.ts under select combined with include:

Test Asserts
$project retains to-many relation alias { name: 1, posts: 1, _id: 0 }
$project retains to-one relation alias { title: 1, author: 1, _id: 0 }
$project retains _id when explicitly selected alongside includes { _id: 1, name: 1, posts: 1 }

Summary

The fix ensures that combining .select() with .include() in MongoDB queries preserves the included relations in the final aggregation result.

Behavior

.select() + .include()
        │
        ▼
     $lookup
        │
        ▼
     $project
        │
        ├── selected scalar fields
        └── included relation aliases
        │
        ▼
   Correct result

Summary by CodeRabbit

  • Bug Fixes

    • Relations included alongside selected fields now remain available in query results.
    • Corrected _id handling when combining field selection with relation includes.
  • Tests

    • Added coverage for to-one and to-many relations combined with selected fields.
    • Added verification for implicit and explicit _id selection behavior.

…clude are combined

When chaining .select() and .include(), the compiled $project stage
only projected selectedFields, dropping relation aliases produced by
$lookup. Add included relation names to the projection so joined
data is preserved in the returned document.

Signed-off-by: rajat12826 <pariharrajat078@gmail.com>
@rajat12826
rajat12826 requested a review from a team as a code owner August 30, 2026 07:51
@CLAassistant

CLAassistant commented Aug 30, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 05113708-2fcc-4729-b67a-0bcc69b0b62c

📥 Commits

Reviewing files that changed from the base of the PR and between ca8fe14 and 3ec078c.

📒 Files selected for processing (2)
  • packages/2-mongo-family/5-query-builders/orm/src/compile.ts
  • packages/2-mongo-family/5-query-builders/orm/test/compile.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The MongoDB ORM compiler now retains included relation aliases in projections built from selected fields. Tests cover to-many and to-one relations, including implicit and explicit _id behavior.

Changes

Projection relation retention

Layer / File(s) Summary
Projection compiler and coverage
packages/2-mongo-family/5-query-builders/orm/src/compile.ts, packages/2-mongo-family/5-query-builders/orm/test/compile.test.ts
The compiler adds each included relation alias to the projection. Tests cover to-many and to-one includes, implicit _id suppression, and explicit _id selection.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Merge Risk: ⚪ Minimal · up to 3ec07

The change preserves included relation fields when scalar selection is combined with relation inclusion. It is localized and covered by targeted tests, so no actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: aqrln

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main fix: preserving joined relation fields when MongoDB ORM queries combine .select() and .include().
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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.

fix(mongo-orm): .select() combined with .include() drops joined relation fields via $project stage

2 participants