Doctrine MongoDB where two fields are equal - mongodb

How do you create a where condition in Doctrine ODM to find only documents where two fields are equal?
A document exists with two int fields alpha and beta, I want to select all documents where these two fields are equal.
I've tried the following but it returns no results:
$qb = $this->createQueryBuilder();
$qb
->field('alpha')->in($alphaIds)
->where('this.alpha === this.beta')
->sort('id', 'DESC');
return $qb->getQuery()->execute();
This questions shows how to do it outside of Doctrine where alpha and beta are not equal https://stackoverflow.com/a/8433182/1283381

Use the Query Expressions in Doctrine\MongoDB\Query\Expr class to create the where() expression via the expr() method as follows:
$qb = $this->createQueryBuilder();
$qb->addAnd(
$qb->expr()
->field('alpha')->in($alphaIds)
->where('this.alpha === this.beta')
)
->sort('id', 'DESC');
return $qb->getQuery()->execute();

Related

How to replace usage of group() & reduce() deprecated ODM query methods into Symfony code

I am using Symfony Doctrine Mongodb-odm 1.2 library in the project. group() & reduce() methods are deprecated and no longer available with MongoDB 4.2. My existing code has used these methods to group and pull the MongoDB records using custom reduce logic on the query. Refer the following query:
$customers = $this->createQueryBuilder($business)
->field('pay_status')->equals('unpaid')
->group(['contact' => 0], ['total' => 0])
->reduce(
'function (obj, prev) {
prev.total += obj.total.amount;
prev.contact_data = obj.contact_data;
if (obj.contact) {
prev.contact = obj.contact.$id.str;
}
return prev;
}'
)
->limit(5)
->getQuery()
->execute()
->toArray(false);
This works completely fine with MongoDB 4.0 and returns the result set with top 5 unpaid customers list. Now, I am struggling to find out the replacement for this query using aggregation pipeline which is recommended for MongoDB 4.2.
Can anyone help with the replacement query using aggregation builder methods? I know how to group the result using aggregation stage but not sure how to pull the top 5 customers without reduce() method here. Thanks in advance.
I guess I found the way to query & retrieve the expected result set using aggregation builder without reduce method:
$customers = $this->createAggregationBuilder($business)
->hydrate(false)
->match()
->field('pay_status')->equals('unpaid')
->group()
->field('_id')->expression(['contact_data'=>'$contact_data','contact'=>'$contact'])
->field('total')->sum('$total.amount')
->project()
->field('total')->expression('$total')
->field('contact')->expression('$_id.contact')
->field('contact_data')->expression('$_id.contact_data')
->field('_id')->expression('$$REMOVE')
->sort(['total' => 'desc'])
->limit(5)
->getQuery()
->execute()
->toArray(false);

Doctrine ORM zend framework entitymanager findby multiple conditions

I'm querying the database with 2 findby's, is there a way to do it in one findby with 2 conditions?
$this->entityManager->getRepository(User::class)->findOneByConfirmtoken($token)
&& $this->entityManager->getRepository(User::class)->findOneById($id)
->findBy([
'property1' => 'value1',
'property2' => 'value2',
])
See the docs about using conditions
You can pass the array of values to findBy method. I also recommend you write your own repositories in specific cases. It is useful for more complex queries. In this case it would be looks like:
public function findOneByIdAndConfirmationToken(int $userId, string $confirmationToken): ?User
{
return $this->getEntityManager()
->createQueryBuilder()
->select('u')
->from(User::class, 'u')
->where('u.id = :userId')
->andWhere('u.confirmationToken = :confirmationToken')
->setParameter('userId', $userId, PDO::PARAM_INT)
->setParameter('confirmationToken', $confirmationToken, PDO::PARAM_STR)
->getQuery()
->getOneOrNullResult();
}

Doctrine MongoDB Query Builder addOr query not returning any results

I'm working on super simple search across multiple fields in a document to see if any of them has a single value. (Note: some fields are using regex to search if value is contained in string). Using query builder I constructed the following.
public function search($value, $limit, $offset=0, $orderby = '', $order='' )
{
$regexVal = new \MongoRegex('/^.*(\b'.str_replace(' ', '\s', $value).'\b).*?$/i');
$query = $this->repository->createQueryBuilder();
$query->addOr($query->expr()->field('location')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.name')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.first_name')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.last_name')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.email')->equals($value));
$query->addOr($query->expr()->field('email')->equals($value));
$query->addOr($query->expr()->field('organization')->equals($value));
$query->limit($limit)
->skip($offset);
if( ! empty($orderby) && $order ){
$query->sort($orderby, $order);
}
return $query->getQuery()->execute();
}
If I dump out the constructed query values I get the following array in this gist. https://gist.github.com/jchamb/04a0400c989cd28b1841 The extra association field in there is being added by a Doctrine Filter.
Through Query builder I don't get any results, however if I construct the query myself and run it in an admin app like genghis, I get the expected single document result.
Actual written mongodb string looks like this. https://gist.github.com/jchamb/ce60829480576a88290d
This project is a zend2 app that was already using doctrine and mongo. I'm not much of an expert with mongo in general so I'm not sure what i'm doing wrong inside of Query Builder that i'm not getting the same result as executing the query directly. I can't find any info on stack or the query builder docs that gives any extra clues for the multiple addOrs syntax either.
Any help or direction would be really appreciated, in the most basic form I need query builder to get a document where association = x and ( field1 = val or field2 = value).
Thanks!
Really unsure what the exact issue was with the above, but after playing around, switching the order of query builder around fixes the problem.
public function search($value, $limit, $offset=0, $orderby = '', $order='' )
{
$regexVal = new \MongoRegex('/^.*(\b'.str_replace(' ', '\s', $value).'\b).*?$/i');
$query = $this->repository->createQueryBuilder()
->find()
->limit($limit)
->skip($offset);
$query->addOr($query->expr()->field('location')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.name')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.first_name')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.last_name')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.email')->equals($value));
$query->addOr($query->expr()->field('email')->equals($value));
$query->addOr($query->expr()->field('organization')->equals($value));
if( ! empty($orderby) && $order ){
$query->sort($orderby, $order);
}
return $query->getQuery()->execute();
}
Would love to still hear some feedback about why this works and the above didn't if anyone know more about the internals of query builder.

Is it possible to use sort() on multiple fields in Doctrine 2 ODM?

I am doing a query on a result document in my doctrine mongodb *odm*. There are two indexed fields in the document which I would like to use in sort. I have written something like:
$results = $this->createQueryBuilder('Document\Score')
->sort('finalScore', 'desc')
->sort('date', 'desc')
->getQuery()
->execute();
Here the second sort() function overrides the first one and the designated result is never found.
Thanks in advance for the nice help.
Try this
$qb = $this->createQueryBuilder('Document\Score');
$qb->sort(array(
'finalScore' => 'desc',
'date' => 'desc',
));
$results = $qb->getQuery()->execute();

Querying by nested references values in mongodb / doctrine2 odm

Hello ive got the following code:
$primer = function($dm, $className, $fieldName, $ids, $hints) {
$repository = $dm->getRepository($className);
$qb = $repository->createQueryBuilder()
->field('id')->in($ids)
->field('images')->prime(true);
$query = $qb->getQuery();
$query->execute()->toArray();
};
$qb = $followRepo
->createQueryBuilder()
->field('isActive')->equals(true)
->field('target')->prime($primer)
->field('follower')->references($return['user'])
->field('target.$ref')->equals('boards')
->field('target.createdBy.type')->equals('user') // here i dont know how to handle this
->sort('created', 'desc')
Is it even possible in mongo to query via target.createdBy.type?
target.createdBy is also ref.
Yes, it is possible to query on sub document properties using the dot notation, as per
the official documentation. I am pretty sure it wont work with a referencing in 1 step though.