Skip to content

Unexpected behaviour when laravel 12 and passport 12 with mongodb 5.4 #3371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
faisaltkr opened this issue Apr 23, 2025 · 8 comments
Closed

Comments

@faisaltkr
Copy link

  • Laravel-mongodb Version: 5.3 and above
  • PHP Version: 8.2 and above
  • Database Driver & Version: mongodb

Description: When we installing passport with mongodb, the _id is storing as string

Steps to reproduce

  1. Install laravel 12 and mongodb 5.3 and above and install laravel-passport
  2. After configuring the passport try to add same requests at a time to generate access_token
  3. follow mongodb laravel-passport setup doc : https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/user-authentication/#laravel-passport

Expected behaviour

{
    "_id" : ObjectId("67af1b54cab5260f0e02c45e"),
    "id" : "2d5975c24790106151a359b50cd65e8df24d667c45198c9543d8a730d4f3b2a3acbd5e6ac9b9de3b",
    "user_id" : "5fd345d8881f551ed73033a2",
    "client_id" : "678f73cda02347dc38027792",
    "scopes" : "[]",
    "revoked" : false,
    "created_at" : ISODate("2025-02-14T10:30:44.163+0000"),
    "updated_at" : ISODate("2025-02-14T10:30:44.198+0000"),
    "expires_at" : ISODate("2025-08-14T10:30:44.163+0000"),
    "name" : "example-token"
}

Actual behaviour

{
    "_id" : "2d5975c24790106151a359b50cd65e8df24d667c45198c9543d8a730d4f3b2a3acbd5e6ac9b9de3b",
    "user_id" : "5fd345d8881f551ed73033a2",
    "client_id" : "678f73cda02347dc38027792",
    "scopes" : "[]",
    "revoked" : false,
    "created_at" : ISODate("2025-02-14T10:30:44.163+0000"),
    "updated_at" : ISODate("2025-02-14T10:30:44.198+0000"),
    "expires_at" : ISODate("2025-08-14T10:30:44.163+0000"),
    "name" : "example-token"
}
@spidfire
Copy link

I'm experiencing a similar issue where the collection documents have both the _id and id
and if i turn on the https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/fundamentals/connection/connection-options/#disable-use-of-id-field-name-conversion
It doesn't disable the rename alias feature in the queries.

\MongoDB\Laravel\Query\Builder::aliasIdForQuery
I would expect ($root || $this->connection->getRenameEmbeddedIdField()) to should have been meant to be $root && ...

@LNDev
Copy link

LNDev commented May 5, 2025

Maybe \MongoDB\Laravel\Query\Builder::compileWheres :

            // Compatibility with Eloquent queries that uses "id" instead of MongoDB's _id
            if ($where['column'] === 'id') {
                $where['column'] = '_id';
            }

should also be changed to:

            // Compatibility with Eloquent queries that uses "id" instead of MongoDB's _id
            if ($where['column'] === 'id' && $this->connection->getRenameEmbeddedIdField()) {
                $where['column'] = '_id';
            }

@GromNaN
Copy link
Member

GromNaN commented May 6, 2025

I'm experiencing a similar issue where the collection documents have both the _id and id

This is something we can't support in this library while maintaining good compatibility with Eloquent SQL. But I understand that some existing databases are made that way; and you need to deal with them.

I would expect ($root || $this->connection->getRenameEmbeddedIdField()) to should have been meant to be $root && ...

No, that would do the opposite of what the option name tell. That would convert id to _id only for the root document when the option is true.

Expected behaviour

   "_id" : ObjectId("67af1b54cab5260f0e02c45e"),
   "id" : "2d5975c24790106151a359b50cd65e8df24d667c45198c9543d8a730d4f3b2a3acbd5e6ac9b9de3b",

Actual behaviour

   "_id" : "2d5975c24790106151a359b50cd65e8df24d667c45198c9543d8a730d4f3b2a3acbd5e6ac9b9de3b",

@faisaltkr If the application provides an identifier, why do you need to generate an ObjectId? What is the behavior with a SQL database?

Maybe \MongoDB\Laravel\Query\Builder::compileWheres :

@LNDev Could you open a pull-request with a failing test case, so we can work on a solution?

@LNDev
Copy link

LNDev commented May 7, 2025

@GromNaN from what I’ve observed, the issue arises when queries are performed using the "id" field on collections where the values of _"id" and "id" are different. In such cases, querying by "id" returns an empty result.

For example:

ExampleModel::where('id', $id);

returns an empty result.

This happens due to three main reasons:

First, the method getRenameEmbeddedIdField() returns true by default if the rename_embedded_id_field setting is not defined in the config/database.php file.

Second, in the methods "aliasIdForQuery" and "aliasIdForResult", if rename_embedded_id_field is not defined or is explicitly set to true or explicitly set to false (in any way, then), the "id" field is always internally converted to "_id" (in root). As a result, any query targeting "id" actually ends up querying "_id".

Third, during the compilation of the "where" clause by the "compileWheres" method, the "id" column is again transformed into "_id". This means that any condition written on "id" is effectively applied to "_id" instead.

@faisaltkr
Copy link
Author

The previous version (4.8) was working as the expected result but the current version(5.4) is removed the ObjectId and replaced with a string. Now it is working fine

@spidfire
Copy link

spidfire commented May 7, 2025

@faisaltkr so people who used to use the _id and id as separate values must just stay in the past and never upgrade to 5.x ?

@LNDev
Copy link

LNDev commented May 7, 2025

I have opened a new issue : #3380

@alcaeus
Copy link
Member

alcaeus commented May 7, 2025

so people who used to use the _id and id as separate values must just stay in the past and never upgrade to 5.x ?

No - they should look at what value they primarily use (_id vs. id), then make sure that the _id field has that value and remove the id field. This can be done in a single query. Here's an example for the MongoDB shell that sets the _id field to the value of the id field:

db.coll.updateMany([], [{"$set": { _id: "$id" }}, {"$unset": "id"}])

We are trying to do away with an old design decision we inherited when taking over this library. This decision led to several issues, including having two "identifiers" with different values. The primary key in MongoDB is always _id, whereas Eloquent always assumes the primary key to be named id, and this latter key was used for a long time. We proposed making the name of the primary key configurable in Eloquent (see laravel/framework#48089), which would've allowed you to fall back to id as primary key during a transitional period, but this idea was rejected and we had to create our own workaround.

@GromNaN GromNaN closed this as not planned Won't fix, can't repro, duplicate, stale May 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants