#php #mysql #laravel #eloquent #entity-attribute-value
#php #mysql #laravel #красноречивый #сущность-атрибут-значение
Вопрос:
Я пытаюсь разработать модель post, которая имеет отношение «один ко многим» с моделью postmeta (включая id
столбцы , post_id
, meta_key
, meta_value
), а также имеет отношение «многие ко многим» с моделью term (включая term_id
и некоторые другие столбцы, а также таблицу post_term, включая id
post_postId
term_term_term_id
столбцы, ,).
Я создал форму, которая содержит некоторые post_metas и термины для поиска и фильтрации моих сообщений.
В этом примере PHP-кода показано, что я использовал:
$posts_query = Post::where('post_type', 'add')->where('author', Auth::id())->where(function ($q0) use($filter_metas){
foreach ($filter_metas as $index => $meta) {
$q0->whereHas('postmetas', function ($q0) use ($index,$meta) {
$q0->where('meta_key', $index)->where('meta_value', $meta);
});
}
});
и это выполняемый запрос для получения результатов.
select * from `posts` where `post_type` = ? and `author` = ? and (exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` in (?, ?, ?, ?)) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` in (?, ?, ?)) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` > ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` = ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` = ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` = ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` = ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` = ?) and exists (select * from `postmeta` where `posts`.`postId` = `postmeta`.`post_id` and `meta_key` = ? and `meta_value` = ?)
Я могу получить правильные результаты из этого запроса, но запрос выполняется слишком медленно, и это моя главная проблема. Существуют ли какие-либо альтернативные подходы?
Комментарии:
1. Старайтесь не использовать whereHas, если у вас больше записей с номерами. Добавьте индексы, если вы действительно хотите использовать whereHas. Я столкнулся с той же проблемой ранее, и я использовал объединения.
2. Привет и спасибо за ваш комментарий, не могли бы вы объяснить это немного подробнее? Или просто поделитесь примером того, как это сделать со мной?
Ответ №1:
Вы можете использовать единый объединенный запрос с агрегацией для фильтрации по мета-атрибутам каждого сообщения
$posts = Post::select(['posts.postId','posts.name'])
->where('post_type', 'add')
->where('author', Auth::id())
->join('postmeta', 'posts.postId', '=', 'postmeta.post_id')
->groupBy('posts.postId','posts.name')
->where(function ($query) use ($filter_metas) {
foreach ($filter_metas as $index => $meta) {
$query->havingRaw('sum(case when meta_key = ? and meta_value = ? then 1 else 0 end) > 0', [$index, $meta]);
}
});
В приведенной выше havingRaw
части запроса это ключ, он будет условно отфильтровывать сообщения, которые не соответствуют метаинформации,
Ответ №2:
Попробуйте этот код, не уверен, работает ли он, надеюсь, вы сможете понять идею.
$posts_query = Post::where('post_type', 'add')
->where('author', Auth::id())
->leftJoin('postmeta', function($join){
$join->on('posts.postId', 'postmeta.post_id');
})
->where(function ($query) use ($filter_metas) {
foreach ($filter_metas as $index => $meta) {
$query->where('postmeta.meta_key', $index)
->where('postmeta.meta_value', $meta);
}
});
Комментарии:
1. Спасибо за ваш ответ, но этот запрос не решает мою проблему. Когда я объединяю таблицы, каждая строка имеет один meta_key, поэтому, когда я использую ‘и’ для исследования разных meta_keys, нет строки, которая имела бы, например, meta_key=a и meta_key=b .