无法规范化查询:BadValue $或/ $和/ $条目都需要是完整对象 - Doctrine

I am trying to covert this query

db.getCollection('queues').find({
    $and:[
        {queue: 'testo'},
        {$or: [
            {$and: [{reserved_at: null}, {available_at:{'$lte':1490323024}}]},
            {reserved_at:{'$lte':1490323024}}
        ]}
    ]
});

to doctrine but I am getting this error.

Can't canonicalize query: BadValue $or/$and/$nor entries need to be full objects.

This is what I tried.

$builder = $this->get('doctrine_mongodb')->getManager()->createQueryBuilder('AppBundle:Ticket');

$builder->findAndUpdate()->addAnd([
    $builder->field('queue')->equals($queue),
    $builder->addOr([
        $builder->addAnd([
            $builder->field('reservedAt')->equals(null),
            $builder->field('availableAt')->lte($currentTime)
        ]),
        $builder->field('reservedAt')->lte($expiration)
    ])
])
->sort('id', 'ASC')
->limit(1)
->field('reservedAt')->set($currentTime->getTimestamp());

$job = $builder->getQuery()->execute()->toArray();

Whats wrong with this code can someone give me any hint.

I'm not familiar with Doctrine's ODM, but since it has a QueryBuilder I assume it also has a method expr() similar to the ORM-QueryBuilder:

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html#the-expr-class

With the expr-class you can build nested queries like this:

->where(
    $builder->expr()->or(
        $builder->expr()->and(
            $builder->expr()->isNull('reservedAt'),
            $builder->expr()->lte('availableAt', $currentTime),
        ),
        $builder->expr()->lte('reservedAt', $expirationDate)
    )
);

It's because you're adding your nested conditions to the original QueryBuilder object. Even when you're using the addAnd and addOr methods with nested parameters, you're still mutating the top level builder, so it's getting confused about what you're trying to do with those conditions.

Try something like this:

$builder
    ->findAndUpdate()
    ->addAnd([
        $builder->expr()->field('queue')->equals($queue),
        $builder->expr()->addOr([
            $builder->expr()->addAnd([
                $builder->expr()->field('reservedAt')->equals(null),
                $builder->expr()->field('availableAt')->lte($currentTime)
            ]),
            $builder->expr()->field('reservedAt')->lte($expiration)
        ])
    ]);

It's important to understand what expr() does, it is nothing but a simple factory method that creates an Expression object that has nothing to do with the builder object that called it.

$builder->expr()

Is the equivalent of

(new Expr())

It's the addAnd and addOr methods that tie everything neatly together. The expr() method is just there so the maintainer of the querybuilder can worry about the class and dependency injection of your Expression, but for someone who doesn't know the builder very well it can obfuscate the importance of the expr() method.

I had similar kind of issue of bad value whle applying $or and $and together just take an example of my code it might help you it was resolved while solving $condition array:

$condition['$or'] = [
            ['assigned_to' => (int)$id,
                'type' => "customer",
                'assigned_date' => ['$gte'=>$mDate],
            ],
            ['assigned_to' => 0,
                'read' => 'no',
                'type' => "customer",
                'assigned_date' => ['$gte'=>$mDate],
            ]
        ];

issue only in formation of Array.I used Mongo with PHP class.