My question is quite simple but I can't manage to find an answer.
When I execute a query like:
$query->select('t2.name as t2_name, t1.name as t1_name')
->from('table1 t1')
->leftJoin('t1.table2 t2')
->execute(array(), Doctrine_Core::HYDRATE_ARRAY);
Doctrine returns me an array like:
array(
[0] => array(
't1_name' => 'foo',
't2_name' => 'bar'
)
)
Where i expected to get field t2_name to be set in the array before t1_name.
Is there anyway to keep the order of these selected fields in Doctrine ?
Doctrine will automatically include the primary (root) table's key field and automatically make it the first column in any query, in almost all hydration types.
Since table1 is the root table in your query, it moves that to the beginning for its own internal processing benefits.
I find this behavior annoying and somewhat unpredictable at times also, but have found great relief by creating custom hydrators.
There's a good example of creating a key/value hydrator which I have used beneficially many times in our code.
You could do something similar to rearrange the fields in the order you want.
Also I have posted an explanation to a very similar question here which may be beneficial.
Related
I'm currently working on a Symfony project, using Doctrine to manage entities.
I have a table named User, containing a few columns, and then another table named Tag, containing a foreign key to that User table with a ManyToOne relation based on the user id, and a single other column named value.
In my app, I need to find a list of users, depending on one of the Tag row, AND the value of one of the User's column. Let's resume :
Select all users where user.value equals somevalue AND Tag.value equals anothervalue.
As I never used Symfony nor Doctrine before this project, I searched into Doctrine documentation and found about the Query Builder. So, I did this :
EDIT : The way I was doing it was kinda weird, so I modified it and here is the result :
public function findByTagAndApp($tag, $app)
{
$em = $this->getEntityManager();
$qb = $em
->getRepository('APIBundle:User')
->createQueryBuilder('u')
->leftJoin('APIBundle\Entity\Tag', 't')
->where('u.application = :app')
->andWhere('t.tag = :tag')
->setParameter('tag', $tag)
->setParameter('app', $app)
;
$users = $qb->getQuery()->getResult();
return $users;
}
And it seems like it works, but in a strange way. Instead of returning an array of User items, which is what I want, it returns an array of array of User items. The first array is always containing two entries, and these two entries are always identical : they are the array I need, without a single difference.
I tried to do return $users[0] instead of just users, and then I can manipulate my User entities the intended way. I could keep it this way as it is working, but I'd really like to know why it returns an unneeded array of array instead of just the array I want. It might be my query, but I'm not sure how to modify it to get only the Users I want.
Any clues on why it behave like this would be really appreciated, as I'm still learning about Doctrine. Thanks !
EDIT² : Nevermind, this query seems completely incorrect too, as I got all users according to the $app value, but it seems like it never check if there is a row in the Tag table with a value of somevalue associated to a foreign key of the User table..
I don't know exactly why it is but..
I think you have to mention from() like ->from('User', 'u')
for extra you can find here
After a few hours of tweaking, I figured it out using SQL statement on PhpMyAdmin, so I could notice that there was a LOT of things that I was doing wrong :
First, the join was not correct. My goal was to collect users that had a certain value in their own table, AND a value from the Tag table. Using a left join, I was collecting users with their own value OR a the value from the Tag table.
Second : The $app value I was passing was an object of type Application (the Application field in my User table is a foreign key), and the query builder didn't know what to do with it. Passing the app_id instead of the app object solved the problem.
Third : The way I collected result was wrong. Obviously, this query returns an array of User objects. And as I execute this query multiple times in a row, I had an array on which I used array_push to fill it with the data, thinking that pushing array1 with array2 would put array2 values into array1, but it was just putting array2 into array1, resulting to that array of arrays that was the initial problem. Using array_merge instead of array_push, I am now able to collect all the results from the queries into a single array. A little array_unique on that to avoid redundancy, and everything is working as expected.
Thanks to everyone who replied !
problem
I have two data tables SEQUENCES and ORGANISMS whose many-to-many-relationship is mappend in the table SOURCES. There is also a 1-m relationshipt between SOURCES and ENTRIES. I will append a detailed structure.
What i want to achieve, is the display of all sequences with all associated organisms and entries, where a condition within the sequences table is met. I have some ideas on how to achieve this, but i need the solution with the best performance, as each of these contains 50k+ entries.
idea one
Select all organisms that belong to the same sequence as a concatenated string in sql, and split it in PHP. I have no idea though, how to do the concatenation in SQL.
idea two
select same sequences with different organisms as distinct records, order by organism, and join them later in php. though this somehow feels just wrong.
idea three
use views. ANY idea on this one appreciated
structure
SEQUENCES
SEQUENCE_ID
DESCRIPTION
ORGANISMS
ORGANISM_ID
NAME
SOURCES
SOURCE_ID
SEQUENCE_ID FK to SEQUENCES.SEQUENCE_ID
ORGANISM_ID FK to ORGANISMS.ORGANISM_ID
ENTRIES
SOURCE_ID FK to SOURCES.SOURCE_ID
ENTRY_VALUE
desired outcome
array(
array(
"SEQUENCE_ID" => 4,
"DESCRIPTION" => "Some sequence",
"SOURCES" => array(
array(
"ORGANISM_ID" => 562,
"ORGANISM_NAME" => "Escherichia coli",
"ENTRIES" => array(
"some entry",
"some other entry"
),
array(
"ORGANISM_ID" => 402764,
"ORGANISM_NAME" => "Aranicola sp. EP18",
"ENTRIES" => array()
)
)
),
array(
"SEQUENCE_ID" => 5,
.....
)
)
PHP5 and FIREBIRD2.5.1
You can't fetch a nested array like that directly from a flat table structure. But if I get you right, what you want to do is not that hard to achieve.
I don't understand why you would concatenate things and then split them again, that's hard to maintain and probably slow.
I see two approaches here:
Fetch everything at once as flat table using JOIN and loop through it in PHP. This approach creates a lot of duplication but it's fast because you can fetch all data in one query and then process it with PHP.
Fetch every entity separately, loop and fetch the next hierarchy level as you go. This approach will be slower. It takes complexity away from the SQL query and doesn't fetch redunant data. It also gives you more freedom as to how you loop through your data and what you do with it.
Alternatively you might want to actually store hierarchical data in a no-sql way, where you could already store the array structure you mentioned.
I have two entities in Doctrine 2.1: Category and Site each category has many sites and each site has a parent category.
I would like to make a single update query (in DQL) which will update a field called count of the Category entity with the number of related sites.
So in SQL I would do something like this:
UPDATE categories c SET c.count = (SELECT COUNT(s.id) FROM sites s WHERE s.category_id = c.id);
This would work beautifuly, in DQL it might something like this:
UPDATE PackageNameBundle:Category c SET c.count = (SELECT COUNT(s.id) FROM PackageNameBundle:Site s WHERE s.category = c)
Such attempt raises [Syntax Error] line 0, col 61: Error: Expected Literal, got 'SELECT'.
Subqueries DO work in DQL, but the problem here (as far as I see it) is that Doctrine cannot assign the returned value from the subquery, to the c.count. This is understandable since I might fetch more than 1 field in the subquery and even more than one row. It magicaly works in MySQL since it sees one row, one field and for convenience returns a single integer value. Doctrine on the other hand has to be object oriented and has to work with different engines where such convertions might not be supported.
Finally, my question is:
What is the best way to do this in Doctrine, should I go with Native SQL or it can be done with DQL and how?
Thanks in advance!
EDIT: I just found this quote in the DQL Docs:
References to related entities are only possible in the WHERE clause and using sub-selects.
So, I guess assigning anything but a scalar value is impossible?
The main question remains though..
You can use native sql queries in Doctrine also, for that kind of specific queries. DQL is powerful in its own way, but it's also limited due to performance constraints. Using native sql queries and mapping the results will achieve the same thing, and there is no disadvantage in doing that.
The documentation explains it in detail.
Ok to make it more clear:
I am Using doctrine
I have a table Brands and Products
Brand
id
name
Product
id
name
brand_id
I have a lot of brands and Products of those brands in the database.
I would like to retrieve List of brands(+ count of its products) Grouped by Brand.name's first latter.
ex:
array(
n => array(
0 => array('Nike', 4 ),
1 => array('North Pole', 18)
.....
)
.....
)
So my question was can this be done with one query in a efficient way.
I really don't wan't to run separate queries for each brand.name's first latter.
Doctrines "Hierarchical Data" cross my mind but I believe it for different thing?.
thanks
If you are going to use this form of result more than once, it might be worthwhile to make the formatting into a Hydrator, as described here.
In your case, you can create a query that select 3 columns
first letter of brand.name
brand.name
count(product.id)
Then hydrate the result
$results = $q->execute(array(), 'group_by_first_column');
You cannot take it from database in that way, but you can fetch data as objects or arrays and then transform it to described form. Use foreach loops.
When using Doctrine you can also use raw SQL querys and hydrate arrays instead of objects. So my Solution would be to use a native SQL Query:
SELECT
brand.name,
count(product.id)
FROM
brand
JOIN
product ON
brand.id=product.brand_id
GROUP BY
brand.id ORDER BY brand.name;
And then iterate in PHP over the result to build the desired array. Because the Result is ordered by Brand Name this is quite easy. If you wasn't to keep database abstraction I think it should also be possible to express this query in DQL, just hydrate an array instead of objects.
I am (as most ) coming from a mySQL background trying to switch over to noSQL and mongoDB. Since denormalization is a part of noSQL since joins is impossible, here's how I would design a simple blog:
array (
blog_title => 'my blogpost',
'date' => '2010-09-05',
comments => array (
'1' => 'Such a good post!!! You deserve a nobel prize'
)
);
If I want to update the comments, adding a new element in that array, how can I make sure that this is done and not the whole comments array being overwritten if multiple users are trying to write a comment at the same time?
Is it the push function I am looking after in mongoDB?
Correct, the $push operator allows you to update an existing array. You can use the $pushAll operator to add multiple values in a single query.
To add a comment to your example document, the query would be:
db.posts.update({blog_title: "my blogpost"}, {$push: {comments: "New comment"}})
These operators are atomic, so you won't run into any problems if multiple users add comments simultaneously.