Reputation: 740
We have a table called content and size of table is over 5Gb. Our Yii2 backend application has a section to view those content and there are few filters available to filter out contents. I need to filter contents which are assigned or not assigned to categories.
Relations
A Content can be shared within many categories. So there is a one to many relationship between Content and Category tables.
Mapping table is content_cat_xref.
Models are as follows.
Content model
/**
* @return \yii\db\ActiveQuery
*/
public function getContentCatXrefs()
{
return $this->hasMany(ContentCatXref::className(), ['content_id' => 'id']);
}
Content_cat_xref model
/**
* @return \yii\db\ActiveQuery
*/
public function getCategory()
{
return $this->hasOne(Category::className(), ['id' => 'category_id']);
}
/**
* @return \yii\db\ActiveQuery
*/
public function getContent()
{
return $this->hasOne(Content::className(), ['id' => 'content_id']);
}
Controller
public function actionIndex()
{
$searchModel = new \common\models\ContentSearch();
$dataProvider = $searchModel->searchMedia(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider
]);
}
ContentSearch Model
public function searchMedia($params)
{
$query = Content::find()->where(['file_type_id'=>[1,2,3,4,5,6,8,11]]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}
//Conditionally add filters
if(isset($this->is_category_available) && $this->is_category_available === 'yes'){
$query = $query->joinWith(['contentCatXrefs' => function($queryw){
$queryw->andWhere(['is not', 'content_cat_xref.category_id', new \yii\db\Expression('null')]);
}]);
}else if(isset($this->is_category_available) && $this->is_category_available === 'no'){
$query = $query->joinWith(['contentCatXrefs' => function($queryw){
$queryw->andWhere(['is', 'content_cat_xref.category_id', new \yii\db\Expression('null')]);
}]);
}
if(!is_null($this->file_name) && !empty($this->file_name)) {
$query->andWhere("MATCH (file_name) AGAINST (\"".$this->file_name."\" IN NATURAL LANGUAGE MODE)");
}
if(!is_null($this->file_path) && !empty($this->file_path)) {
$query->andWhere("MATCH (file_path) AGAINST (\"".$this->file_path."\" IN NATURAL LANGUAGE MODE)");
}
$query->andFilterWhere(['type_code'=>$this->type_code]);
$query->andFilterWhere(['file_type_id'=>$this->file_type_id]);
$query->andFilterWhere(['content.active_status'=>$this->active_status]);
$query->andFilterWhere(['content.content_status'=>$this->content_status]);
if(is_null($this->file_name)) {
$query->orderBy("id desc");
}
return $dataProvider;
}
I have few questions
What should be the correct and efficient way to join two tables( content and content_cat_xref) to retrieve data. I need to filter contents which are assigned or not assigned to categories. So, I use this filter for that.
if(isset($this->is_category_available) && $this->is_category_available === 'yes'){
$query = $query->joinWith(['contentCatXrefs' => function($queryw){
$queryw->andWhere(['is not', 'content_cat_xref.category_id', new \yii\db\Expression('null')]);
}]);
}else if(isset($this->is_category_available) && $this->is_category_available === 'no'){
$query = $query->joinWith(['contentCatXrefs' => function($queryw){
$queryw->andWhere(['is', 'content_cat_xref.category_id', new \yii\db\Expression('null')]);
}]);
}
I use eager loading to improve performance here. But It gives duplicate records when joining these two tables. After I use distinct then it reduce the performance. What should be the correct way to do this Yii2?
Is there are way to pass params to relation functions when constructing query in content search model?
If we order content by id descending, again reduce the performance.
It is highly appreciated if there is anyone who can provide guidance on this.
Upvotes: 0
Views: 489
Reputation: 655
if($this->is_category_available == 'yes') { return $this->hasMany(ContentCatXref::className(), ['content_id' => 'id']) ->andOnCondition(['a_type' => 1]); } else { return $this->hasMany(ContentCatXref::className(), ['content_id' => 'id']) ->andOnCondition(['a_type' => 0]); }
Upvotes: 1