doctrine / mongodb-odm

The Official PHP MongoDB ORM/ODM
https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/
MIT License
1.09k stars 504 forks source link

QueryBuilder is replacing "id" by "_id" when filtering on a hash field #2550

Open thomas-negrault opened 1 year ago

thomas-negrault commented 1 year ago
Q A
Version 2.5.2

Support Question

I am using this lib with DoctrineMongoDBBundle.

I store Stripe subscription into my User document. Users has a subscription embed document which has a stripeSubscription hash, which is the json provided by Stripe

Here is my mapping:

#[MongoDB\Document(collection: 'users', repositoryClass: UserRepository::class)]
class User
{
    #[MongoDB\EmbedOne(targetDocument: Subscription::class)]
    protected Subscription $subscription;
#[MongoDB\EmbeddedDocument]
class Subscription
{
    #[MongoDB\Field(type: Type::HASH, nullable: true)]
    protected null|array $stripeSubscription;

Here is a sample of my User document:

{
    _id: '1e4dc99cccd03b0898029756790625a4',
   subscription: {
        stripeSubscription: {
            id: 'sub_123',
            object: 'subscription',
            ...
        }
   }
}

I want to fetch users by subscription.stripeSubscription.id so I did:

        $subscriptionId="sub_123";
        $queryBuilder = $this->createQueryBuilder();
        $queryBuilder->field("subscription.stripeSubscription.id")->equals($subscriptionId);

        return $queryBuilder
            ->getQuery()
            ->getSingleResult();

But in the profiler, the formatted query is:

{
    "find": "users",
    "filter": {
        "subscription.stripeSubscription._id": "sub_123"
    },
    "limit": {
        "$numberInt": "1"
    },
    "$db": "myDb",
    "lsid": {
        "id": {
            "$binary": {
                "base64": "HWzvsCWeTlad1CBKpMSAuw==",
                "subType": "04"
            }
        }
    }
}

So my ->field("subscription.stripeSubscription.id") is converted to subscription.stripeSubscription._id with _id instead of id and it does not find my user.

Am I missing something here ? Is there an option to filter with a field containing .id without rewriting to ._id ?

Edit: I found a workaround, it's not perfect as it does 2 queries (one to find it and the other one to return an hydrated Document) but it does work:

$dbName = $this->getDocumentManager()->getConfiguration()->getDefaultDB();
$mongoClient = $this->getDocumentManager()->getClient();
$collection = $mongoClient->selectDatabase($dbName)->selectCollection('users');
$userArray = $collection->findOne(['subscription.stripeSubscription.id' => $subscriptionId]);

$user = $this->find($userArray['_id']);
malarzm commented 1 year ago

I believe this resembles https://github.com/doctrine/mongodb-odm/issues/2531#issuecomment-1531749604