Skip to content

Conversation

@AymenReIn
Copy link

@AymenReIn AymenReIn commented Jan 28, 2026

Summary

Adds a new alias_id connection config option (default: true) that allows disabling the automatic top-level _idid aliasing introduced in v5.0.

  • When alias_id is false, root-level id is treated as a regular field and not converted to/from _id
  • When alias_id is true (default), behavior is identical to current — zero breaking changes
  • When disabling alias_id, also set rename_embedded_id_field to false to prevent compound query operators ($and/$or) from incorrectly aliasing root-level id fields in nested where clauses

Problem

Applications upgrading from v4 to v5 that have documents with a business id field (e.g., external API IDs, legacy system identifiers) alongside MongoDB's _id experience data corruption because the aliasing overwrites the custom id field with _id.

The existing rename_embedded_id_field config (v5.3+) only controls embedded document aliasing. There is currently no way to disable top-level aliasing, which has been reported in:

Changes

File Change
src/Connection.php New aliasId property, getter/setter, config init ('alias_id' => true)
src/Query/Builder.php compileWheres(): gate id_id column rename on getAliasId()
src/Query/Builder.php aliasIdForQuery(): separate root aliasing (alias_id) from embedded aliasing (rename_embedded_id_field)
src/Query/Builder.php aliasIdForResult(): same separation for result processing
src/Eloquent/DocumentModel.php getIdAttribute(): return actual id attribute without _id fallback when disabled
src/Eloquent/DocumentModel.php getKeyName(): return _id as primary key when disabled
src/Eloquent/DocumentModel.php getKey(): return raw _id attribute directly, bypassing accessor

Config usage

// config/database.php
'mongodb' => [
    'driver' => 'mongodb',
    'dsn' => env('MONGODB_URI'),
    'database' => env('MONGODB_DATABASE'),
    'alias_id' => false,
    'rename_embedded_id_field' => false,
],

Or at runtime:

DB::connection('mongodb')->setAliasId(false);
DB::connection('mongodb')->setRenameEmbeddedIdField(false);

Why both config keys?

The aliasIdForQuery() method recurses into nested arrays with root=false. Compound query operators like $and/$or (automatically added by SoftDeletes or multiple where() clauses) create nested array structures that are incorrectly treated as embedded documents during recursion. Setting rename_embedded_id_field to false prevents this from converting root-level id to _id inside these query structures.

Test plan

  • All existing tests pass unchanged (default alias_id => true)
  • Verified with integration tests: model lifecycle (create, refresh, query, update), query builder insert, raw MongoDB document verification, soft deletes with compound where clauses

@AymenReIn AymenReIn requested a review from a team as a code owner January 28, 2026 08:55
@AymenReIn AymenReIn requested a review from GromNaN January 28, 2026 08:55
@AymenReIn AymenReIn force-pushed the feature/alias-id-config branch from d72c9c9 to 085cfcb Compare January 28, 2026 10:35
Adds a new `alias_id` connection config (default: true) that controls
whether the driver converts `id` to `_id` at the top level for queries
and results.

When `alias_id` is false, applications should also set
`rename_embedded_id_field` to false to prevent nested query operators
($and/$or) from incorrectly aliasing root-level `id` fields.

Changes:
- Connection: add aliasId property, getAliasId()/setAliasId() methods
- Builder: gate compileWheres id->_id rename on getAliasId()
- Builder: gate aliasIdForQuery root-level aliasing on getAliasId()
- Builder: gate aliasIdForResult root-level aliasing on getAliasId()
- DocumentModel: getIdAttribute() returns actual 'id' attribute
  without falling back to '_id' when alias_id is disabled
- DocumentModel: getKeyName() returns '_id' when alias_id is disabled
- DocumentModel: getKey() returns raw '_id' attribute directly to
  bypass getIdAttribute accessor when alias_id is disabled
@AymenReIn AymenReIn force-pushed the feature/alias-id-config branch from 085cfcb to a4ec347 Compare January 28, 2026 10:47
The test stub was missing the getAliasId() mock, causing it to return
null/false instead of the default true value. This broke tests that
rely on the default id aliasing behavior.
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.

1 participant