Doctrine2 OneToMany count - doctrine-orm

I have two entities: User and Comment.
In User have:
/**
* #ORM\OneToMany(targetEntity="Comment", mappedBy="User", cascade={"persist", "remove"})
* #ORM\OrderBy({"sort_priority" = "ASC"})
*/
private $Comments;
In my custom class I have query:
$query = 'SELECT u from BackendUserBundle:User u WHERE u.status != 0';
This query return all users but I want return user with count(Comments) >0. I cant use Join because I using iterate().

OK I found in Doctrine docs:
http://docs.doctrine-project.org/en/2.1/reference/dql-doctrine-query-language.html
createQuery('SELECT u FROM CmsUser u WHERE
SIZE(u.phonenumbers) > 1'); $users = $query->getResult();

Related

Need Doctrine Many to Many QueryBuilder Query to Return NOT In Common Rows

I have two tables 1) Prices and 2) Users
Owner is a column in the Prices table.
Both tables have a many to many relationship between price.users and users.price.
The query below returns all Prices shared by owner1 and user1.
Question: How do I fix this query where it only returns all owner1 prices that are not synced with user1.
If I use ->andWhere('u.id = :user1Id') then I get only records for user1.
If I use ->andWhere('u.id != :user1Id') then I get all owner record including user1 records.
Again I want all owner records except those that are synced with user1.
I've tried the following so far:
1) $queryUsersPrices
->innerJoin('p.owner', 'o')
->leftJoin('p.users', 'u')
->andWhere('o.id = :ownerId')
/*I need to Remove records for u.id from results*/
->andWhere('u.id = :user1Id')
->setParameter('owner1Id', $owner->getId())
->setParameter('user1Id', $user->getId());
$userPrices = $queryUsersPrices->getQuery()->getResult();
2) $userPrices = $repository->createQueryBuilder($alias);
$userPrices
->select("u.prices")
->from("Price","p")
->innerJoin('p.users', 'u')
->andWhere('u.id = :userId')
->getDQL();
$query = $repository->createQueryBuilder($alias);
$query
->innerJoin($alias . '.owner', 'o')
->innerJoin($alias . '.priceType', 'pt')
->innerJoin($alias . '.model', 'm')
->where(
$query->expr()->not(
$query->expr()->in(
'p.id',
$userPrices
)
)
)
->andWhere('m.status = :m_status')
->andWhere('o.id = :adminId')
->andWhere('pt.site <> 1')
->setParameter('m_status', Model::STATUS_ACTIVE);
$result = $query->getQuery()->getResult();
3) $query = $repository->createQueryBuilder($alias);
$query
->innerJoin($alias . '.owner', 'o')
->innerJoin($alias . '.users', 'u', 'WITH', 'u.id =
:userId')
->innerJoin($alias . '.priceType', 'pt')
->innerJoin($alias . '.model', 'm')
->where('m.status = :m_status')
->andWhere('o.id = :adminId')
->andWhere('u.id IS NULL')
->andWhere('pt.site <> 1')
->setParameter('adminId', $adminUser->getId())
->setParameter('userId', $user->getId())
->setParameter('m_status', Model::STATUS_ACTIVE);
$test = $query->getQuery()->getResult();
Method #1 results in user1 prices only
Method #2 results in this error: Error: Method Doctrine\Common\Collections\ArrayCollection::__toString() must not throw an exception, caught Symfony\Component\Debug\Exception\ContextErrorException: Catchable Fatal Error: Object of class Doctrine\ORM\EntityManager could not be converted to string
Methos #3 results in owner prices only
THIS IS WHAT ACTUALLY WORKED BASED ON M Khalid Junaid ANSWER
$userPrices = $repository->createQueryBuilder('pr')
->innerJoin('pr.users', 'u')
->andWhere('u.id = :userId')
->setParameter('userId', $user->getId())
->getDQL();
$query = $repository->createQueryBuilder($alias);
$query
->innerJoin($alias . '.owner', 'o')
->innerJoin($alias . '.priceType', 'pt')
->innerJoin($alias . '.model', 'm')
->where(
$query->expr()->not(
$query->expr()->in(
$alias . '.id',
$userPrices
)
)
)
->andWhere('m.status = :m_status')
->andWhere('o.id = :adminId')
->andWhere('pt.site <> 1')
->setParameter('m_status', Model::STATUS_ACTIVE)
->setParameter('adminId', $adminUser->getId())
->setParameter('userId', $user->getId());
$result = $query->getQuery()->getResult();
I would suggest to break down your logic as
First select prices that belongs to $user->getId() as
$userPrices = $this->createQueryBuilder("u")
->select("u.prices")
->from("YourBundleName:Prices","p")
->innerJoin('p.users', 'u')
->andWhere('u.id = :user1Id')
->getDQL();
Then get prices for owner which is $owner->getId() and exclude prices from the subquery for $user->getId() as
$qb = $this->createQueryBuilder("pr");
$qb->select("pr")
->from("YourBundleName:Price", "pr")
->innerJoin('pr.owner', 'o')
->where(
$qb->expr()->not(
$qb->expr()->in(
"pr.id",
$userPrices
)
)
)
->andWhere('o.id = :ownerId')
->setParameter('owner1Id', $owner->getId())
->setParameter('user1Id', $user->getId())
;
$query = $qb->getQuery();
$result = $query->getResult();
This would be more like to your original query but not the exact one I guess and might need some tweaks as per your mappings, but will give you an idea to move forward with this
References
Doctrine EXIST and NOT EXIST
Doctrine Query Builder nested orX and andX conditions with join
I guess that would be very handy to transform your logic directly in DQL by doing a left join with price.users and with additional filter clause in joining part so that it will join only rows for price where user id is $user->getId() and to exclude these prices which belongs to $user->getId() we can use a where clause as u.id IS NULL
DQL
SELECT p
FROM Price p
JOIN p.owners o
LEFT JOIN p.users u WITH u.id = :user1Id
WHERE u.id IS NULL
AND o.id = :ownerId
Query builder will be like
$qb = $this->createQueryBuilder("p")
->select("p")
->from("Price", "p")
->innerJoin('p.owner', 'o')
->leftJoin(
'p.users',
'u',
'WITH',
'u.id = :user1Id'
)
->where('u.id IS NULL')
->andWhere('o.id = :ownerId')
->setParameter('owner1Id', $owner->getId())
->setParameter('user1Id', $user->getId())
;
$query = $qb->getQuery();
$result = $query->getResult();

Add Literal Percent Sign (%) to my calculation inside raw query Django

I get an error when I add a percentage symbol in the query:
Exception Type:IndexError
Exception Value:tuple index out of range.
views.py
class groupdatagercekzamanliveriListView(ListAPIView):
query2 = gercekzamanlıveri.objects.raw("""SELECT 1 as id,
CONCAT(ROUND((SUM(net_uretim_miktari)/SUM(teorik_uretim_miktari)::float*100)),'%') as tee, FROM tee_gercekzamanlıveri
INNER JOIN tee_isyerleri ON tee_gercekzamanlıveri.isyeri_id= tee_isyerleri.id
INNER JOIN tee_malzemeler ON tee_gercekzamanlıveri.malzeme_id= tee_malzemeler.id
INNER JOIN tee_isyerimalzemebilgileri ON tee_isyerimalzemebilgileri.isyeri_id= tee_gercekzamanlıveri.isyeri_id
AND tee_isyerimalzemebilgileri .malzeme_id = tee_gercekzamanlıveri.malzeme_id) as a GROUP BY isyeri_id""")
queryset = query2
serializer_class = groupdatagercekzamanlıveriserializer
serializer.py
class groupdatagercekzamanlıveriserializer(serializers.Serializer):
id = serializers.IntegerField()
tee = serializers.CharField()
When I use "a" as string for "%" no problem:
CONCAT(ROUND((SUM(net_uretim_miktari)/SUM(teorik_uretim_miktari)::float*100)),'a') as tee
Result: "tee": 80a
According to the documentation (GIYF first hit for django sql "%" - at least for me) you have to double it to have the character recognized as a literal, e.g.:
--
CONCAT(
ROUND(
(SUM(net_uretim_miktari) / SUM(teorik_uretim_miktari)::float * 100)
),
'%%'
) as tee, FROM tee_gercekzamanlıveri
--

Doctrine 2 multi-level inheritance - how to define the join

I have two tables:
Email:
id message
1 This is an email message
Activity:
id related_id related_type
66 1 email
72 1 booking
74 55 booking
In a query builder I want to join Email.id to Activity.related_id only if related_type is 'email'.
I therefore have Entity Activity:
/**
* Activity
*
* #ORM\Table(name="activity")
* #ORM\Entity
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="related_type", type="string")
* #ORM\DiscriminatorMap( {"email" = "Email"} )
*/
class Activity
And Entity Email:
/**
* Email
*
* #ORM\Table(name="email", indexes={#ORM\Index(name="contact_id_index", columns={"contact_id"})})
* #ORM\Entity(repositoryClass="Cinolla\ApiBundle\Entity\EmailRepository")
*/
class Email extends Activity
However, looking at the query that doctrine is generating at the moment, it's doing:
FROM email t0 INNER JOIN activity t1 ON t0.id = t1.id
Whereas it should be doing:
FROM email t0 INNER JOIN activity t1 ON t1.related_id = t0.id AND t1.related_type = 'email'
Where do I define that Email should be joined on related_id?
Why has it not included the AND t1.related_type = 'email'?

cleaning up my SQLAlchemy operations (reducing repetition)

I have some server side processing of some data (client-side library = jQuery DataTables)
I am using POST as my ajax method. In my Flask webapp, I can access the POST data with request.values
The data type / structure of request.values is werkzeug.datastructures.CombinedMultiDict
If the user wants to sort a column, the request contains a key called action with a value of filter (note the below printouts are obtained with for v in request.values: print v, request.values[v])
...
columns[7][data] role
columns[8][search][regex] false
action filter
columns[10][name]
columns[3][search][value]
...
all the column names are also contained in the request as keys. The columns that have search terms will have the search string as a value for the column name key (as opposed to empty for columns with no search term entered. So, If I want to search for firstname containing bill, I would see the following in my request
columns[7][searchable] true
...
columns[6][name]
firstname bill
columns[0][search][value]
columns[2][searchable] true
...
columns[5][data] phone
role
columns[10][data] registered_on
...
columns[0][searchable] true
email
columns[7][orderable] true
...
columns[2][search][value]
Notice how role and email are empty. So my code below is very non-DRY
rv = request.values
if rv.get('action') == 'filter':
if len(rv.get('firstname')):
q = q.filter(User.firstname.ilike('%{0}%'.format(rv.get('firstname'))))
if len(rv.get('lastname')):
q = q.filter(User.lastname.ilike('%{0}%'.format(rv.get('lastname'))))
if len(rv.get('username')):
q = q.filter(User.username.ilike('%{0}%'.format(rv.get('username'))))
if len(rv.get('email')):
q = q.filter(User.email.ilike('%{0}%'.format(rv.get('email'))))
if len(rv.get('phone')):
q = q.filter(User.phone.ilike('%{0}%'.format(rv.get('phone'))))
if len(rv.get('region')):
q = q.filter(User.region.name.ilike('%{0}%'.format(rv.get('region'))))
if len(rv.get('role')):
q = q.filter(User.role.name.ilike('%{0}%'.format(rv.get('role'))))
if len(rv.get('is_active')):
q = q.filter(User.is_active_ == '{0}'.format(rv.get('is_active')))
if len(rv.get('is_confirmed')):
q = q.filter(User.is_confirmed == '{0}'.format(rv.get('is_confirmed')))
if len(rv.get('registered_on_from')):
fdate = datetime.strptime(rv.get('registered_on_from'), '%Y-%m-%d')
q = q.filter(User.registered_on > fdate)
if len(rv.get('registered_on_to')):
tdate = datetime.strptime(rv.get('registered_on_to'), '%Y-%m-%d')
q = q.filter(User.registered_on < tdate)
I was building the sorting functionality, and I found the following statement that greatly simplified my life (see this answer)
q = q.order_by('{name} {dir}'.format(name=sort_col_name, dir=sort_dir))
I was wondering if there was a way to simplify this set of filtering queries like the above sorting code since I will have to do this for many other models.
This should help:
from sqlalchemy import inspect
from sqlalchemy.sql.sqltypes import String,Boolean
def filter_model_by_request(qry,model,rv):
if rv.get('action') == 'filter':
mapper = inspect(model).attrs # model mapper
col_names = list(set([c.key for c in mapper]) & set(rv.keys()))
# col_names is a list generated by intersecting the request values and model column names
for col_name in col_names:
col = mapper[col_name].columns[0]
col_type = type(col.type)
if col_type == String: # filter for String
qry = qry.filter(col.ilike('%{0}%'.format(rv.get(col_name))))
elif col_type == Boolean: # filter for Boolean
qry = qry.filter(col == '{0}'.format(rv.get(col_name)))
return qry
Example call (I used it with a #app.before_request and a cURL call to verify):
qry = db.session.query(User)
print filter_model_by_request(qry,User,request.values).count()
The date range filtering is not included in the function, add this feature if you wish, your code is fine for that purpose.
side note: be careful with the bigger/smaller operators for the dates. You're excluding the actual requested dates. Use <= or >= to include dates in filtering action. It's always a pitfall for me..

convert sql query form to django orm

I Have a models like this :
class Person(models.Model):
person_id=models.AutoField(primary_key=True)
person_name=models.CharField(max_length=100)
person_family=models.CharField(max_length=100)
person_father=models.ForeignKey('Person', related_name='child_from_father',null=True)
person_mother=models.ForeignKey('Person', related_name='child_from_mother',null=True)
def __str__(self):
return self.person_family
class Car(models.Model):
car_id=models.AutoField(primary_key=True)
car_name=models.CharField(max_length=100)
car_owner=models.ForeignKey(Person)
def __str__(self):
return self.car_name
there is some query that i want the orm form :
1: select person_name from Person
2: select *
from Person,Car
where car_owner=person_id
3: select *
from Person,Car
group_by(person_name)
4: select *
from Person,Car
where name like %x%
group_by(person_name)
having car_id >= 2
and at last do u know any good refrence for orm
thx for help
I'm assuming the group by is for ordering. If you really want group_by look at aggregates and annotate in django. My guess of what you are looking for is:
1: Get the person record - select person_name from Person
person = Person.objects.get(<WHERE clause>).values('person_name')
2: select *
from Person,Car
where car_owner=person_id
Get the cars belonging to the person
cars = Car.objects.filter(car_owner = person)
3: select *
from Person,Car
group_by(person_name)
Get list of cars sorted by owner
car_list = Car.objects.all().order_by('car_owner__person_name')
4: select *
from Person,Car
where name like %x%
group_by(person_name)
having car_id >= 2
List of cars with search criteria
car_list = Car.objects.filter(id__gte = 2, car_name__contains = "<search>").order_by('car_owner__person_name',)
Cars and their Owners
car_list = Car.objects.all().values('car_name','car_owner__person_name')