I have a site developed in cakephp 2.0, I have some tables relationed here is an example:
This is my relations:
ingredients (id,name) has many versions
ingredient_properties(id,property_id,version_id) belongs
to properties, versions
properties (id,name,value,group_id,unit_id) has many
ingredient_properties and belongs to groups,units
groups (id,name) has many properties
units (id,name) has many properties
versions (id,name,ingredient_id,active) has many ingredient_properties and belongs to ingredients.
I am in the ingredientController.php and I wanto to retrieve all this data where Version.active=1 and Version.ingredient_id=2.
This is my query:
$this->set(
'ingredient',
$this->Ingredient->Version->find('all', array(
'recursive' => 2,
'conditions' => array(
'Version.active' => 1,
'Version.ingredient_id' => 2
)
))
);
I have many and many queries like this and I want to know if recursive 2 is the best way to retrieve all data of the table that I have explained or there is a better way most quickly (in terms of speed of query not to implement).
I hope that someone can help me to optimize my code because this query works but I don't know if it is the better way to retrieve data of many tables relationed.
Thanks.
It is not the best way to use 'recursive' => 2 if you want to retrieve so much data. I believe it generates too many queries. Containable behaviour has the same drawback. The best way for me was to unbind models associations and construct table joins on the fly. You can look at an example here. But you need to know some SQL to understand what you do.
Related
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 follower and subscriber project and when a user follows other user, I should inc 1 to follower and inc 1 to subscriber's count
I use these codes to update,
this one is k which is follower's count,
$m->obarax->user->update(array("_id" => $_SESSION["u"]["_id"]),array('$inc' => array("k" => (int)1)));
this one is t which is subscriber's count,
$m->obarax->uye->update(array("_id" => new MongoId($_GET["idi"])),array('$inc' => array("t" => (int)1)));
the thing that bothers me that, I searched a lot, but I could not find a way to merge those two queries into one basic query, Is there a way so I can merge those queries ? thank you :)
You can't merge them since you're updating two different keys on two different documents. Besides that, your collections also differ, but it still not possible even if you were using the same collection because your data will be de-normalized in this case.
I'm using cakephp. In some query I use these kind of find:
$this->Photo->Behaviors->attach('Containable', array('autoFields' => true));
This is the Contain array that i use in the find:
'contain'=>array(
'User'=>array('fields'=>array('User.Name','User.Username')),
'Like' => array('User'=>array('fields'=>'Name'),
'order'=>'Timestamp DESC'
)),
'recursive' => 2,
The problem is that every time i want the Name of User that liked a photo. Cakephp does this query.
For example: SELECT `User`.`Name` FROM `Users` AS `User` WHERE `User`.`id` = 2175
If i have 300 likes on one photo i will make another 300queries for the User.Name. So, I would like to cache this kind of request. I've installed memcache correctly in my server, it's working normally. But I can't find a way to cache the query that cake make with the Containable Behaviors.
Has some one had this problem?
Thanks
G.
Why not use cakephp's counterCache feature instead?
There is a lot of documentation in the cakephp book about caching queries not just in me cache but many other ways as well such. Check out the CakeCache class.
there are a number of approaches on this topic.
if it is only about belongsTo relations it boils down to manually join tables using bindModel().
here is a good behavior: http://planetcakephp.org/aggregator/items/891-linkable-behavior-taking-it-easy-in-your-db
it takes care of that itself.
convert following query into cakephpquery.
"SELECT * FROM user1.user_favourites,esl.esl_lyrics
WHERE
esl_lyrics.id=user_favourites.fav_recordID
AND user_favourites.fav_userID=".$user_id."
AND user_favourites.fav_widgetID=$wid_id";
Models files are esl.php and userFavourite.php
DB are user1 and esl.
DB tables are user_favourites in user1 and esl_lyrics in esl DB.
plz give details.what changes are do in esl.php and userFavourite.php
please Help me...
It will be difficult to determine what to write until you can provide a data map for the various IDs you are using. Since you are not conforming to standards in your SQL, the fields are all named different in the various tables. But here is what I understand so far:
esl_lyrics.id = user_favorites.fav_recordID
From your description there are two models. So you will need to make sure you have relationships between the two. This will require that you determine if it is belongsTo, hasOne, hasMany, etc.
It also appears you are using multiple databases (schemas), so you will need to configure the database.php so that you can access each one.
Once everything is configured you should be able to access the data as:
$this->Model1->Model2->find('all', array('conditions' => array('Model1.id' => 'Model2.id', 'Model2.user_id' => $user_id, 'Model2.widgetID' => $wid_id)));
It will return an array with the data from both models. But until you can share what your models look like and a mapping of ids etc., this will be as good of an answer as you will get.
I have the following relationships set up:
A HABTM B
B belongsTo C
C hasMany B
Now, for a given A, I need all C with the B's attached. I can write the SQL queries, but what's the proper CakePHP way? What method do I call on which model, and with which parameters?
I'd go with Aziz' answer and simply process the data as it comes in. If you need C to be your primary model though, you'll have to do a little workaround. Cake is not terrifically good with conditions on related models yet, especially on removed 3rd cousins kind of queries. It usually only does actual JOIN queries on belongsTo or hasMany relations; not on HABTM relations though, those it gets in separate queries. That means you can't include conditions on related HABTM models.
Your best bet then might be something like this:
// get related records as usual with the condition on A, limit to as little data as necessary
$ids = $this->A->find('first', array(
'conditions' => array('A.id' => 'something'),
'recursive' => 2,
'fields' => array('A.id'),
'contain' => array('B.id', 'B.c_id', 'B.C.id') // not quite sure if B.C.id works, maybe go with B.C instead
));
// find Cs, using the ids we got before as the condition
$Cs = $this->C->find('all', array(
'conditions' => array('C.id' => Set::extract('/B/C/id', $ids)),
'recursive => 1
);
Note that this produces quite a bunch of queries, so it's not really an optimal solution. Writing your own SQL might actually be the cleanest way.
EDIT:
Alternatively, you could re-bind your associations on the fly to make them hasMany/belongsTo relationships, most likely using the join table/model of A and B. That might enable you to use conditions on related models more easily, but it's still tricky to fetch Cs when the condition is on A.
$this->A->find(
'first',
array('conditions'=>array('id'=>'someword'),
'recursive'=>2)
);
like this?
this might work
$this->C->find('all',
array('conditions'=>array('id'=>'someword','B.aid'=>$a.id)));
I'd think of "Containable" behaviour (http://book.cakephp.org/view/474/Containable)... gives a lot control on finding related data.