I have a site developed in cakephp 2.x
I have a query with contain with a very lot of table relationed. I know that the most efficient way to do this big query is to make the join query manually. But I wanted to try with contain. I have selected only the field that I need but at the end I print how much queries inside are created: 5000 queries!! The database take 6-10 second to elaborate this query and I want to optimize time. Has cakephp a method to optimize? I don't want to use join now because there are a lot of join to create. Is possible? I know that is a crazy query with a lot of data but is the main page of the product with a lot of data.
This is the query:
$this->set('product',$this->Product->find('all', array(
'contain' => array(
'Origin' => array(
'fields'=>array('id','diet_id'),
'OriginAlias' => array(
'fields'=>array('id','origin_id','language','alias'),
'conditions' => array('OriginAlias.language' => $lang)
),
'Diet' => array(
'fields'=>array('id'),
'DietAlias' => array(
'fields'=>array('id','diet_id','language','alias'),
'conditions' => array('DietAlias.language' => $lang)
),
)
),
'ProductAlias' => array(
'conditions' => array('ProductAlias.alias' => $alias),
'User' => array(
'fields'=>array('id','username'),
'Profile' => array(
'fields'=>array('id','user_id','country','sex','diet','show_diet'),
),
'UserOptions' => array ('fields' => array ('avatar_type')),
'Avatar' => array ('fields' => array ('filename'))
),
'User2' => array(
'fields'=>array('id','username'),
'Profile' => array(
'fields'=>array('id','user_id','country','sex','diet','show_diet'),
),
'UserOptions' => array ('fields' => array ('avatar_type')),
'Avatar' => array ('fields' => array ('filename'))
)
),
'ProductImage'=> array(
'limit' => 1,
'ProductImageVote'=> array(
'order' => 'ProductImageVote.vote desc'
),
'User' => array(
'fields'=>array('id','username'),
'Profile' => array(
'fields'=>array('id','user_id','country','sex','diet','show_diet'),
),
)
),
'ProductGroupProduct' => array(
'fields'=>array('id','user_id','product_id','product_group_id'),
'ProductGroup'=> array(
'fields'=>array('id','text','language'),
),
),
'ProductIngredientVersion' => array(
'conditions' => $cond_version,
'limit' => 1,
'ProductIngredient' => array(
/*'Product' => array(
'ProductAlias' => array()
),*/
'Ingredient' => array(
'fields'=>array('id','user_id','origin_id','active'),
'IngredientAlias' => array(
'fields'=>array('id','user_id','ingredient_id','edit_user_id','alias'),
),
),
),
),
'ProductVersion' => array(
'conditions' => array('ProductVersion.active' => '1', 'ProductVersion.product_id' => $id),
'limit' => 1,
'ProductProperty' => array(
'Property' => array(
'fields'=>array('id','user_id','group_id','unit_id'),
'PropertyAlias' => array(
'fields'=>array('id','user_id','property_id','alias','language'),
'conditions' => array('PropertyAlias.language' => $lang)
),
'Unit' => array(
'fields'=>array('id','user_id','symbol','active'),
),
'PropertyGroup' => array(
'fields'=>array('id','user_id'),
'PropertyGroupAlias' => array(
'fields'=>array('id','user_id','group_id','alias'),
'conditions' => array('PropertyGroupAlias.language' => $lang)
)
)
),
),
),
'Manufacturer' => array(
'fields'=>array('id','text'),
),
'Brand' => array(
'fields'=>array('id','text'),
),
'UserProductLike' => array(
'conditions' => array('UserProductLike.product_id' => $id),
),
'UserProductHate' => array(
'conditions' => array('UserProductHate.product_id' => $id),
),
),
'conditions' => array('Product.id' => $id)
)));
Related
I have an taxonomy that may be have one or more items with selection. Is possible on WP_Query with tax_query and specify if can get results with relation 'OR' that is possible or select A or B (for example) using the same parametter?
if (isset($_GET['area']) && !empty($_GET['area'])) {
if(is_array($_GET['area'])) {
foreach($_GET['area'] as $a) {
$tax_query[] = array(
'taxonomy' => 'property_area',
'field' => 'slug',
'terms' => array($a),
);
}
}
}
Because on this query the final SQL may be:
AND tt1.term_taxonomy_id IN (232) AND tt2.term_taxonomy_id IN (250)
And if was with relation OR the results is the same.
Because on sample:
$args = array(
'post_type' => 'post',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => array( 'quotes' ),
),
array(
'relation' => 'AND',
array(
'taxonomy' => 'post_format',
'field' => 'slug',
'terms' => array( 'post-format-quote' ),
),
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => array( 'wisdom' ),
),
),
),
);
$query = new WP_Query( $args );
Is possible to make and like "sub tax_query" srictly doing an relation 'OR'?
hello I want to get results from multiple tables using the keyword which user has typed. The problem I am having is I don't know how can I do search on that table which is getting through contain
Here's my query
public function getGigPostBasedOnSearch($keyword){
$this->Behaviors->attach('Containable');
return $this->find('all', array(
'contain' => array(
'User','UserInfo', 'GigPostAndCategory.Category','Location','GigPostAndCalender'
),
'conditions' => array(
'AND' => array(
'GigPost.active' => 1,
'OR' => array(
array('GigPost.title LIKE' => '%'.$keyword.'%'),
array('GigPost.description LIKE' => '%'.$keyword.'%'),
array('Location.location_string LIKE' => '%'.$keyword.'%'),
)
)
//'OrderGigPost.request' => 0
),
'order' => 'GigPost.gig_post_id DESC',
'recursive' => 0
));
}
This query works fine. I want to search keyword in category table also.I want to do something like this
array('Category.cat_name LIKE' => '%'.$keyword.'%')
Please help me how can I search in Category table as well
Thank you
Model GigPost.php
<?php
class GigPost extends AppModel
{
public $useTable = 'gig_post';
public $primaryKey = 'gig_post_id';
public $hasAndBelongsToMany = array(
'Category' =>
array(
'className' => 'Category',
'joinTable' => 'gigpost_category',
'foreignKey' => 'gig_post_id',
'associationForeignKey' => 'cat_id',
'unique' => true,
)
);
public $hasOne = array(
'Location' => array(
'className' => 'Location',
'foreignKey' => 'gig_post_id',
'conditions' => array('GigPost.gig_post_id = Location.gig_post_id')
));
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'fields' => array('User.user_id','User.email','User.active')
),
'UserInfo' => array(
'className' => 'UserInfo',
'foreignKey' => 'user_id',
)
);
public function getGigPostBasedOnSearch($keyword){
$this->Behaviors->attach('Containable');
return $this->find('all', array(
'contain' => array(
'User','UserInfo', 'GigPostAndCategory.Category'=>array(
'conditions'=>array(
'OR' => array(
array('Category.cat_name' => '%'.$keyword.'%'),
),
)
),'Location','GigPostAndCalender'
),
'conditions' => array(
'AND' => array(
'GigPost.active' => 1,
'OR' => array(
array('GigPost.title LIKE' => '%'.$keyword.'%'),
array('GigPost.description LIKE' => '%'.$keyword.'%'),
array('Location.location_string LIKE' => '%'.$keyword.'%'),
// array('Category.cat_name LIKE' => '%'.$keyword.'%'),
)
)
//'OrderGigPost.request' => 0
),
'order' => 'GigPost.gig_post_id DESC',
'recursive' => 0
));
}
}
Your issue is that the relationship between GigPost and Category is HABTM, so when you use contain Cake has to do a separate query to retrieve the related categories as there is not a one-on-one association. To get round this you need to manually perform a join rather than contain the categories:-
$this->find('all', array(
'contain' => array(
'User', 'UserInfo', 'GigPostAndCategory.Category', 'Location', 'GigPostAndCalender'
),
'joins' => array(
array(
'table' => 'gigpost_category',
'alias' => 'GigPostCategory',
'type' => 'INNER',
'conditions' => 'GigPost.id = GigPostCategory.gig_post_id'
),
array(
'table' => 'categories',
'alias' => 'Category',
'type' => 'INNER',
'conditions' => 'Category.id = GigPostCategory.cat_id'
)
),
'conditions' => array(
'AND' => array(
'GigPost.active' => 1,
'OR' => array(
array('GigPost.title LIKE' => '%'.$keyword.'%'),
array('GigPost.description LIKE' => '%'.$keyword.'%'),
array('Location.location_string LIKE' => '%'.$keyword.'%'),
array('Category.cat_name LIKE' => '%'.$keyword.'%'),
)
)
),
'order' => 'GigPost.gig_post_id DESC',
'group' => 'GigPost.id',
'recursive' => 0
));
This ensures that the categories will be included with the data returned by the primary query.
You will probably need to modify the joins array a bit as you don't appear to be using Cake naming conventions for your table so I am not sure what you have named things. However, this should put you on the right track.
I have the following CakePHP code; I want it to return all rows (two in this case)
public function orderdetails($orderId)
{
$Productsaleslist = $this->Productsales->find('all', array(
'joins' => array(
array(
'table' => 'product',
'alias' => 'prod',
'type' => 'INNER',
'conditions' => array(
'prod.id = Productsales.product_id'
)
),
array(
'table' => 'sales_order_address',
'alias' => 'sod',
'type' => 'INNER',
'conditions' => array(
'sod.id = Productsales.sales_order_address_id'
)
),
),
'fields' => array(
'Productsales.*',
'prod.name',
'prod.image_url',
'sod.*'
),
'conditions' => array(
'Productsales.product_sales_slno' => $orderId
)
)
);
$this->set('Productsaleslist', $Productsaleslist);
}
$orderId comes from a URL parameter, and it contains the value of product_sales_slno (RAJ201701211485025418). This should retrieve two integers, but I'm only getting one as shown below.
How can I fix this?
in my model 'mesn' i have belongsto relations:
public $belongsTo = array(
'Order' => array(
'className' => 'Order', 'foreignKey' => 'order_id', 'conditions' => '', 'fields' => '', 'order' => ''
), 'SaleOrder' => array(
'className' => 'SaleOrder', 'foreignKey' => 'sale_order_id', 'conditions' => '', 'fields' => '',
'order' => ''
), 'ShippedBox' => array(
'className' => 'Box', 'foreignKey' => 'shipped_box_id', 'conditions' => '', 'fields' => '',
'order' => ''
)
); /* * * hasMany associations** #var array
In one of my model-functions i want to join another table on the "belongsto" "ShippedBox" (table: boxes). But doesn't matter how i try to write the join i get an error message of unknown column:
$arr_s_result = $this->find('all', array(
'joins' => array(
array('table' => 'shipments',
'alias' => 'MyShipments',
'type' => 'INNER',
'conditions' => array(
'MyShipments.id = ShippedBox.shipment_id'
)
)),
'conditions' => array('Mesn.name' => $arr_search), 'recursive' => 0
));
I have tried:
'MyShipments.id = ShippedBox.shipment_id'
and
'MyShipments.id = box.shipment_id'
and even
'MyShipments.id = Boxes.shipment_id'
where the table "boxes" with the field "shipment_id" exists.
How can i get this join working?
'MyShipments.id = box.shipment_id'
to:
'MyShipments.id = Box.shipment_id'
Also what about this:
$arr_s_result = $this->find('all', array(
'conditions' => array('Mesn.name' => $arr_search), 'recursive' => 0
));
The belongsTo join is done automatically.
I think you'll need to do something like use subqueries to get what you want -
$arr_s_result = $this->find('all', array(
'joins' => array(
array('table' => '(SELECT boxes.id, [enter other fields you need here] FROM shipments JOIN boxes ON boxes.shipment_id = shipments .id)',
'alias' => 'MyShipments',
'type' => 'INNER',
'conditions' => array(
'Mens.shipped_box_id = MyShipments.id'
)
)),
'conditions' => array('Mesn.name' => $arr_search), 'recursive' => 0
));
I have the following models:
-> = 1:many, <-> = many:many
User<->Product->MessageList<->Message
My goal with this query is to find all messages corresponding to the logged in . I also filter out messages that have been read (I find the messages ids in the prior find and store them in $messageIdsReadByPerson).
Here is my attempt:
// only grab messages belonging to this user
$this->Message->unbindModel(array('hasAndBelongsToMany'=>array('MessageListsMessage')));
$this->Message->bindModel( array(
'hasOne' => array(
'MessageListsMessage' => array(
'className' => 'MessageListsMessage',
'foreignKey' => false,
'type' => 'INNER',
'conditions' => array(
'MessageListsMessage.message_id = Message.id'
)
),
'MessageList' => array(
'className' => 'MessageList',
'foreignKey' => false,
'type' => 'INNER',
'conditions' => array(
'MessageList.id = MessageListsMessage.message_list_id'
)
),
'Product' => array(
'className' => 'Product',
'foreignKey' => false,
'type' => 'INNER',
'conditions' => array(
'Product.id = MessageList.product_id'
)
),
'ProductsUser' => array(
'className' => 'ProductsUser',
'foreignKey' => false,
'type' => 'INNER',
'conditions' => array(
'ProductsUser.product_id = Product.id'
)
),
'User' => array(
'className' => 'User',
'foreignKey' => false,
'conditions' => array(
'User.id = ProductsUser.user_id',
'User.id' => $this->Auth->user('id')
)
)
)
));
$messages = $this->Message->find('all', array(
'recursive' => -1
));
$this->set('messages', $messages);
But that only gives this query:
SELECT `Message`.`id`, `Message`.`text`, `Message`.`url` FROM `messages` AS `Message` WHERE 1 = 1
How can this be done properly using bindModel (or some easier method that I'm unaware of, although joins is apparently not the way to go).
EDIT:
this doesnt work either:
function index() {
// only grab messages belonging to this user
$messages = $this->Message->find('all', array(
'contain' => array(
'MessageList' => array(
'Product' => array(
'User.id = ' . $this->Auth->user('id')
)
)
)
));
$this->set('messages', $messages);
}
I think the same answer applies as I just gave here:
How to get only products with images in CakePhp
containable or recursive higher