Preventing associated queries on a hasMany model with find - php

I have a model that has several hasMany associations to other models. One thing I have noticed is that when I make a query against the parent table, all of the associated tables are queried as well. For performances sake, I would like to prevent this, as I do not need this data on every call to the parent model.
This is my current parent model:
class UserEntity extends UserAgentAppModel {
var $name = 'UserEntity';
var $primaryKey = 'entity_id';
var $actsAs = array('EavEntity');
var $validate = array(
'user_name'=>array(
'rule'=>'isUnique',
'message'=>'This username has already been taken. Please try again'
),
'user_pass' => array(
'rule' => array('between', 8, 16),
'message' => 'Passwords must be between 8 and 16 characters long.')
);
var $hasMany = array(
'UserEntityVarchar' => array(
'className' => 'UserEntityVarchar',
'foreignKey' => 'entity_id',
'isEav' => 'true'
),
'UserEntityDatetime' => array(
'className' => 'UserEntityDatetime',
'foreignKey' => 'entity_id',
'isEav' => 'true'
),
'UserEntityInteger' => array(
'className' => 'UserEntityInteger',
'foreignKey' => 'entity_id',
'isEav' => 'true'
),
'UserEntityBoolean' => array(
'className' => 'UserEntityBoolean',
'foreignKey' => 'entity_id',
'isEav' => 'true'
),
'UserEntityArray' => array(
'className' => 'UserEntityArray',
'foreignKey' => 'entity_id',
'isEav' => 'true'
)
);
);?>
This is what I am seeing in the query log. The issue I am seeing is that queries 12-17 always occur when using find. However, I am using a behavior to pull this data from my eav model.
1 SHOW FULL COLUMNS FROM `user_entities` 8 8 1
2 SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME= 'latin1_swedish_ci'; 1 1 1
3 SHOW FULL COLUMNS FROM `user_entity_varchars` 4 4 1
4 SHOW FULL COLUMNS FROM `user_entity_datetimes` 4 4 1
5 SHOW FULL COLUMNS FROM `user_entity_integers` 4 4 1
6 SHOW FULL COLUMNS FROM `user_entity_booleans` 4 4 1
7 SHOW FULL COLUMNS FROM `user_entity_arrays` 4 4 1
12 SELECT `UserEntity`.`entity_id`, `UserEntity`.`user_name`, `UserEntity`.`user_pass`, `UserEntity`.`user_status`, `UserEntity`.`user_group`, `UserEntity`.`instance_id`, `UserEntity`.`is_logged_in`, `UserEntity`.`is_visible` FROM `user_entities` AS `UserEntity` WHERE 1 = 1 2 2 0
13 SELECT `UserEntityVarchar`.`value_id`, `UserEntityVarchar`.`attribute_id`, `UserEntityVarchar`.`entity_id`, `UserEntityVarchar`.`value` FROM `user_entity_varchars` AS `UserEntityVarchar` WHERE `UserEntityVarchar`.`entity_id` IN (1, 2) 3 3 0
14 SELECT `UserEntityDatetime`.`value_id`, `UserEntityDatetime`.`attribute_id`, `UserEntityDatetime`.`entity_id`, `UserEntityDatetime`.`value` FROM `user_entity_datetimes` AS `UserEntityDatetime` WHERE `UserEntityDatetime`.`entity_id` IN (1, 2) 0 0 0
15 SELECT `UserEntityInteger`.`value_id`, `UserEntityInteger`.`attribute_id`, `UserEntityInteger`.`entity_id`, `UserEntityInteger`.`value` FROM `user_entity_integers` AS `UserEntityInteger` WHERE `UserEntityInteger`.`entity_id` IN (1, 2) 0 0 0
16 SELECT `UserEntityBoolean`.`value_id`, `UserEntityBoolean`.`attribute_id`, `UserEntityBoolean`.`entity_id`, `UserEntityBoolean`.`value` FROM `user_entity_booleans` AS `UserEntityBoolean` WHERE `UserEntityBoolean`.`entity_id` IN (1, 2) 0 0 0
17 SELECT `UserEntityArray`.`value_id`, `UserEntityArray`.`attribute_id`, `UserEntityArray`.`entity_id`, `UserEntityArray`.`value` FROM `user_entity_arrays` AS `UserEntityArray` WHERE `UserEntityArray`.`entity_id` IN (1, 2) 0 0 0
22 SHOW FULL COLUMNS FROM `eav_attributes` 8 8 1
23 SELECT `EavAttribute`.`attribute_id`, `EavAttribute`.`attribute_code`, `EavAttribute`.`backend_model`, `EavAttribute`.`frontend_input`, `EavAttribute`.`frontend_label`, `EavAttribute`.`is_required`, `EavAttribute`.`is_user_defined`, `EavAttribute`.`is_unique` FROM `eav_attributes` AS `EavAttribute` WHERE `attribute_id` = 5 1 1 0
24 SELECT `EavAttribute`.`attribute_id`, `EavAttribute`.`attribute_code`, `EavAttribute`.`backend_model`, `EavAttribute`.`frontend_input`, `EavAttribute`.`frontend_label`, `EavAttribute`.`is_required`, `EavAttribute`.`is_user_defined`, `EavAttribute`.`is_unique` FROM `eav_attributes` AS `EavAttribute` WHERE `attribute_id` = 6 1 1 0
25 SELECT `EavAttribute`.`attribute_id`, `EavAttribute`.`attribute_code`, `EavAttribute`.`backend_model`, `EavAttribute`.`frontend_input`, `EavAttribute`.`frontend_label`, `EavAttribute`.`is_required`, `EavAttribute`.`is_user_defined`, `EavAttribute`.`is_unique` FROM `eav_attributes` AS `EavAttribute` WHERE `attribute_id` = 7

If you don't want to pull all the hasMany data in your find query set the value of recursive to -1 like in your controller
$results = $this->Model->find('all', 'recursive' => -1));
A better option is to use Containable behavior, this way you can specify which Models to fetch and which not. http://book.cakephp.org/view/1323/Containable

Do proper use of 'recursive' and 'unbind model' very good functionality of cake to restrict your query upto your useful data.
Check here how both works's you will get a better idea.

Related

Cakephp increasing update a column in the act

Good day!
I am running an update on two tables at once , but when I run the query cakephp is increasing the value of a column like a column with auto increment .
I have the following array:
$this->request->data = array(
'Model1' => array(
'id'=>'9',
'nome_fantasia' => 'Campos',
'razao_social' => 'Campos ',
'email' => 'testes#teste.com.br',
'responsavel_cpf' => '4456456465',
'ativo' => '1'
),
'Model2' => array(
(int) 0 => array(
'id' => '43',
'relacionamento_id' => '9',
'endereco' => 'Rua ******',
'numero' => '123',
'bairro' => 'bairro',
'cep' => '033888222'
)
)
);
And then the bass I have the update function:
$this->Modelo1->id = $this->request->data('Modelo1.id');
$this->Modelo1->saveAll( $this->request->data );
Ok , it does the Update in Model1 when it runs the update in Modelo2 it saves all the data but in the ' relacionamento_id ' instead of putting '9' as in this-> request- > data it is increasing with some ghost value. .. I realized that every time I run the query it will increase the number , for example
Attempt 1 = relacionamento_id = 50
Attempt 2 = relacionamento_id = 51
Attempt 3 = relacionamento_id = 52
Attempt 4 = relacionamento_id = 53
If I save both models separately it is right, but I would save direct .

How can i select records from two tables in cake php(cake 2)

I am new to cake php . i have two tables
ce_landing
ce_stat
structure is
ce_stat
id keyword click
1 keyword1 24
2 keyword2 2
3 keyword3 6
ce_landing
id page_keyword
1 keyword1,check,keyword3
2 keyword2,usa,alphanumeric
i want to fetch all the records ce_landing.page_keyword is present in ce_stat.keyword. I am using this in my cake php model
public $hasMany = array(
'Stat' => array(
'className' => 'Stat',
'foreignKey' => 'keywor',
'dependent' => false,
'conditions' => array('Stat.keyword LIKE' => '%Landing.page_keywords%'),
'group' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
but this is generated sql query like
SQL Query: SELECT Stat.id, Stat.customer_id, Stat.account,
Stat.campaign_id, Stat.campaign, Stat.keyword,
Stat.ad_grp_id, Stat.ad_grp, Stat.impressions,
Stat.clicks, Stat.cost, Stat.qualityScore,
Stat.keywordState, Stat.date_from, Stat.date_to,
Stat.user_id, Stat.created, Stat.modified, Stat.keywor
FROM EB_adwords.ce_stats AS Stat WHERE Stat.keyword LIKE
'%Landing.page_keywords%' AND Stat.keyword =
('559f479a-82ac-4e3d-8c24-19b5c0a8011f')
so it returns null data because of AND Stat.keyword =('559f479a-82ac-4e3d-8c24-19b5c0a8011f') conditions.
Update
what i want to get all the records from ce_landing with total clicks according to keywords present . i.e for record 1 in ce_landing. i'll get the result
id page_keyword clicks
1 keyword1,check,keyword3 30
2 keyword2,usa,alphanumeric 2
You needs a SQL statement equivalent to:
SELECT ce_landing.id, ce_landing.page_keyword, SUM(ce_stat.click) AS total_clicks
FROM ce_landing
LEFT JOIN ce_stat
ON FIND_IN_SET(keyword,page_keyword)>0
GROUP BY ce_landing.id, ce_landing.page_keyword;
which does not easily translate to Cakephp's find method. Just use the query method to implement.
$this->Landing->query("SELECT Landing.id, Landing.page_keyword, SUM(ce_stat.click) AS total_clicks
FROM ce_landing AS Landing
LEFT JOIN ce_stat
ON FIND_IN_SET(keyword,page_keyword)>0
GROUP BY Landing.id, Landing.page_keyword;");

Yii: can't use LIMIT in a mysql query

I'm using Yii, and I want to select 5 rows from mysql starting from the third row.
For Example, I have these rows:
ID - NAME
1 - abc
2 - bcd
3 - hdf
4 - fgr
5 - gdf
...
and I want to select 5 rows, starting from the third row.
My code:
$rows = Users::model()->findAll(array(
'order' => 'id DESC',
'limit' => '3, 5'
));
The problem this selects nothing.
There is an offset parameter.
$rows = Users::model()->findAll(array(
'order' => 'id DESC',
'limit' => '5',
'offset' => '3'
));

If column have a row=$variable and in another column on the same row=$variable2 return value 1

Sorry for confusing title. But I don't know how to explain this.(I don't speak that good English)
Here is a picture to make it alittle bit more clear:
http://img823.imageshack.us/img823/8812/edxt.png
If pic_name=328.jpg AND user=myhrmans return value of 1
else if you cant find value user=myhrmans return 0 for example. Anyway I can pull this off?
Thank you :)
Not sure to understand precisely what you mean, but I'm going to make an attempt.
Your query should be written somehow like this one:
SELECT user, pic_name,
IF(user = 'myhrmans' AND pic_name = '328.jpg', 1, 0) AS value
FROM yourtable
WHERE user = myhrmans;
When executed from PHP (and after fetching the values), your query will return this array:
$result = array(
0 => array(
'user' => 'myhrmans',
'pic_name' => '326.jpg',
'value' => 0
),
1 => array(
'user' => 'myhrmans',
'pic_name' => '329.jpg',
'value' => 0
),
2 => array(
'user' => 'myhrmans',
'pic_name' => '328.jpg',
'value' => 1
),
3 => array(
'user' => 'myhrmans',
'pic_name' => '319.jpg',
'value' => 0
)
);
Which, if I understood, approaches what you want.

Retrieve Child Objects

I want a table of comments like so
id | comment | parent_id
--------------------------
1 text1 0
2 text2 1
3 text3 2
4 text4 3
5 text5 3
6 text6 5
I want to construct an array displaying the hierarchy of the parents and children. The tree should go back a undetermined number of generations. I don't want to use nesting foreach loops as I'm not sure how deep it goes. That is why I'm here, I'm not sure of the best practice for a problem like this. I also want to display the depth in the array. Below is an example. It doesn't really relate to table above, but hopefully gives you an idea of what I need.
array(
"depth"=> 4
"parent" => array(
"id"=> 1,
"comment" => "sometext1"
"child_count" => 2,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
),
1 => array(
"id" => 3
"comment" => "sometext3"
"child_count" => 1,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 2,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
),
1 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 1,
"children" => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
)
)
)
)
)
)
)
)
I was going to use foreach and do a SQL statement to retrive that parent/childs children. ie
$sql = "SELECT * FROM comments WHERE parent = $parent_id";
Im not really looking for the code for all this, just a pseudo code solution.
This can be easily done in PHP... For this you need two arrays and a two while loops.
This code will make a tree the way you wanted and for an undetermined depth and number of children.
Pastebin to the working code.
Using references, lets imagine everything is saved in an array $data with this structure: (id, comment, parent_id) where parent_id points to an id.
Code to build the tree.
$tree = array();
reset($data);
while (list($k, $v) = each($data))
if (0 == ($pid = $v['parent_id']))
$tree[$k] =& $data[$k]; else
$data[$pid]['children'][$k] =& $data[$k];
And to generate the depth and child count.
reset($data);
while (list($k, $v) = each($data))
if (0 != $v['parent_id'])
{
$ref =& $data[$k];
$depth = 0;
do
{
if ($depth) $ref =& $data[$ref['parent_id']];
$dre =& $ref['depth'];
if (!isset($dre) || $dre <= $depth) $dre = $depth++;
if (isset($ref['children']))
$ref['child_count'] = count($ref['children']);
else
{
$ref['child_count'] = 0;
$ref['children'] = null;
}
}
while ($ref['parent_id']);
}
All my code has been written on the fly and not even tested, so if there are any errors please forgive meeeeeeeee!!!!!!!!!!! ← Forget that, I tried it, fixed a couple of issues and now works perfectly.
Note
For this code to work, the index of every item has to be equal to its ID.
The array I used to try the code.
$data = array(
'1' => array('id' => '1', 'comment' => 'a', 'parent_id' => 0),
'2' => array('id' => '2', 'comment' => 'b', 'parent_id' => 0),
'3' => array('id' => '3', 'comment' => 'c', 'parent_id' => 1),
'4' => array('id' => '4', 'comment' => 'd', 'parent_id' => 1),
'5' => array('id' => '5', 'comment' => 'e', 'parent_id' => 2),
'6' => array('id' => '6', 'comment' => 'f', 'parent_id' => 2),
'7' => array('id' => '7', 'comment' => 'g', 'parent_id' => 5),
'8' => array('id' => '8', 'comment' => 'h', 'parent_id' => 7)
);
This is the problem when you use Adjacency list for trying to retrieve all child nodes in the hierarchy. It just doesn'y handle recursion very well if you are using mysql. (Oracle is another matter).
Creating the structure is simple, you should not really concern yourself with how to create the array structure just yet, first you want to try and create an efficient query and effiecient models that play perfectly to the type of queries that you will be making.
For example, you say that you want to retrieve all child nodes. Well then you should probably be using nested set models instead or in addition to adjacency list.
Take a look at some of these resources...
Is there a simple way to query the children of a node?
The idea of a nested set, is that you store the lft and right edge values of a node, meaning that retrieving any child nodes, is incredibly simple, beause you just select nodes which have a lft value greater than the target nodes lft value, and smaller than the rgt value.
Once you retrieve your result set, creating your array structure will be effortless.
See here : http://en.wikipedia.org/wiki/Nested_set_model
Once you have your results, then take a look at this question, which I asked a year or so ago, which is exactly what you want. PHP > Form a multi-dimensional array from a nested set model flat array
Example
id | comment | parent_id | lft | rgt |
-------------------------------------------------
1 World null 1 12
2 Europe 1 2 11
3 England 2 3 10
4 Kent 3 4 5
5 Devon 3 6 9
6 Plymouth 5 7 8

Categories