Сложная выборка по TV параметрам в getResources
Доброго времени суток, сообщество!
Хочу поделиться одним небольшим трюком, который позволяет устранить одну, на мой взляд нелогичность в getResources
Как известно, для того чтобы отфильтровать товары (или ещё какие оъекты) по TV параметрам следует использовать tvFilters
Если нам нужно отобрать товары Sony с диагональю 65 или 85 дюймов придётся использовать такую конструкцию
А теперь представим, что нам нужно отобрать товары Sony с диагональю 65 или 85 дюймов черного или серого цвета
Если мы добавим в условие ещё один цвет или размер диагонали начнётся жесть
Дело в том, что при разборе параметра &tvFilters, getResources делит запрос на операторы или (||), а потом на операторы и (,)
На практике же, гораздо чаще требуется, чтобы порядок был обратным
Чуть-чуть подправим getResources
120 строка
Меняем
256 строка
Меняем
312 Строка
Меняем
Таким нехитрым способом гораздо проще реализовывать сложные фильтры, наподобие таких, как реализованы на сайтах Евросети и Эльдорадо
Хочу поделиться одним небольшим трюком, который позволяет устранить одну, на мой взляд нелогичность в getResources
Как известно, для того чтобы отфильтровать товары (или ещё какие оъекты) по TV параметрам следует использовать tvFilters
[[getResources? &tvFilters=`manuf===Sony||manuf===LG`]]
выбрать товары Sony или LG (можно так: manuf===LG||Sony)[[getResources? &tvFilters=`diag===65||diag===85`]]
выбрать товары с диагональю 65 или 85 дюймов[[getResources? &tvFilters=`manuf===Sony,diag===65`]]
выбрать товары Sony c диагональю 65 дюймЕсли нам нужно отобрать товары Sony с диагональю 65 или 85 дюймов придётся использовать такую конструкцию
[[getResources? &tvFilters=`manuf===Sony,diag===65||manuf===Sony,diag===85`]]
А теперь представим, что нам нужно отобрать товары Sony с диагональю 65 или 85 дюймов черного или серого цвета
[[getResources? &tvFilters=`manuf===Sony,diag===65,color===black||manuf===Sony,diag===65,color===gray||manuf===Sony,diag===85,color===black||manuf===Sony,diag===85,color===gray`]]
Если мы добавим в условие ещё один цвет или размер диагонали начнётся жесть
Дело в том, что при разборе параметра &tvFilters, getResources делит запрос на операторы или (||), а потом на операторы и (,)
На практике же, гораздо чаще требуется, чтобы порядок был обратным
[[getResources? &tvFilters=`manuf===Sony,diag===65||85,color===gray||black`]]
согласитесь такая конструкция куда проще, чем та, которая выше и добавление ещё одного условия не составит труда Чуть-чуть подправим getResources
120 строка
Меняем
$tvFilters = !empty($tvFilters) ? explode($tvFiltersOrDelimiter, $tvFilters) : array();
На $tvFilters = !empty($tvFilters) ? explode($tvFiltersAndDelimiter, $tvFilters) : array();
256 строка
Меняем
$filters = explode($tvFiltersAndDelimiter, $tvFilter);
На$filters = explode($tvFiltersOrDelimiter, $tvFilter);
312 Строка
Меняем
if (!empty($conditions)) {
$firstGroup = true;
foreach ($conditions as $cGroup => $c) {
if (is_array($c)) {
$first = true;
foreach ($c as $cond) {
if ($first && !$firstGroup) {
$criteria->condition($criteria->query['where'][0][1], $cond, xPDOQuery::SQL_OR, null, $cGroup);
} else {
$criteria->condition($criteria->query['where'][0][1], $cond, xPDOQuery::SQL_AND, null, $cGroup);
}
$first = false;
}
} else {
$criteria->condition($criteria->query['where'][0][1], $c, $firstGroup ? xPDOQuery::SQL_AND : xPDOQuery::SQL_OR, null, $cGroup);
}
$firstGroup = false;
}
}
На if (!empty($conditions)) {
$firstGroup = true;
foreach ($conditions as $cGroup => $c) {
if (is_array($c)) {
$first = true;
foreach ($c as $cond) {
if ($first && !$firstGroup) {
$criteria->condition($criteria->query['where'][0][1], $cond, xPDOQuery::SQL_AND, null, $cGroup);
} else {
$criteria->condition($criteria->query['where'][0][1], $cond, xPDOQuery::SQL_OR, null, $cGroup);
}
$first = false;
}
} else {
$criteria->condition($criteria->query['where'][0][1], $c, $firstGroup ? xPDOQuery::SQL_OR : xPDOQuery::SQL_AND, null, $cGroup);
}
$firstGroup = false;
}
}
Таким нехитрым способом гораздо проще реализовывать сложные фильтры, наподобие таких, как реализованы на сайтах Евросети и Эльдорадо
Комментарии: 13
Таким нехитрым способом гораздо проще реализовывать сложные фильтры, наподобие таких, как реализованы на сайтах Евросети и ЭльдорадоЧерез getResources?
За сколько у тебя грузится страница с результатами такой фильтрации?
Аjax ответ приходит за 0.3 — 1 сек.
Много?
Заметил, что чем мягче условия поиска, тем дольше приходит ответ. Т.е если сбросить все фильтры, то ответ приходит за секунду. Если составить условия таким образом, что в результате на вывод будет всего пара записей, то ответ сервера 0.3 сек
В базе сейчас примерно 2500 записей
Много?
Заметил, что чем мягче условия поиска, тем дольше приходит ответ. Т.е если сбросить все фильтры, то ответ приходит за секунду. Если составить условия таким образом, что в результате на вывод будет всего пара записей, то ответ сервера 0.3 сек
В базе сейчас примерно 2500 записей
Василий наверное хотел вам порекомендовать pdoResouces
Если устраивает — то вопросов больше нет.
Мне, в своё время, скорость работы getResources показалась неприемлимой.
Мне, в своё время, скорость работы getResources показалась неприемлимой.
Василий, подскажите, есть ли в pdoResources возможность решения подобной задачи без правки кода сниппета?
Ознакомился с документацией pdoTools, но не нашёл там ответ
Конкретно меня интересует возможность смены приоритета работы операторов И и ИЛИ в tvFilters
Ознакомился с документацией pdoTools, но не нашёл там ответ
Конкретно меня интересует возможность смены приоритета работы операторов И и ИЛИ в tvFilters
В pdoResources задача решается несколько иначе:
Вот здесь кратко написано, а вот здесь значительно подробнее.
[[!pdoResources?
&includeTVs=`manuf,diag,color`
&where=`{
"manuf":"Sony",
"diag:IN":[65,85],
"color:IN":["black","gray"]
}`
]]
В принципе, там есть и &tvFilters, но только как временная замена при миграции c getResources. Пользоваться этим параметром я никому не советую — &where гораздо гибче, лучше и удобнее.Вот здесь кратко написано, а вот здесь значительно подробнее.
Спасибо!
Буду пробовать.
Ещё маленький вопросик можно?
Если в OR нам нужен LIKE?
Такое нужно например когда мы используем multiselect TV
Как быть тогда?
Буду пробовать.
Ещё маленький вопросик можно?
Если в OR нам нужен LIKE?
"color:IN":["%black%","%gray%"]
— мне почему-то кажется, что такая констукция работать не будетТакое нужно например когда мы используем multiselect TV
Как быть тогда?
&where=`{
"color:LIKE":"%black%",
"OR:color:LIKE":%gray%"
}`
И вот еще один OR:color:LIKE тут добавить не выйдёт — потому что одинаковых ключей в массиве быть не может. Но можно указывать строки:
&where=`["
color LIKE '%black%' OR color LIKE '%gray%' OR color LIKE '%white%'
"]`
Подробнее про синтаксис where можно прочитать в официальной документации.И очень тебя прошу — почини свой enter, ненужные пустые строки в комментарии выглядят неопрятно.
pdoResources ни как не хочет подхватывать строку $where. Использую вариант с квадратными скобками
$output .= $modx->runSnippet('pdoResources',array(
'includeTVs' => $includeTVs,
'where' => $where,
));
В $where лежит грамотный кусок SQL, сформированный на основе post запроса, обрамлённый квадратными скобками. Например такой"[ TVfo LIKE '%Южный%' AND (TVclient_activity LIKE '%Физ.охрана%' OR TVclient_activity LIKE '%Пультовая охрана%') ]"
На выходе же where игнорируется и я получаю все записи базы. Спору нет, работает быстрее, если сравнивать с getResources c пустым фильтром, но не фильтруется… В логе есть sql запрос, в нём также присутствие $where я не обнаружил
Может там и лежит грамотный кусок SQL, только написан он неграмотно. Посмотри на скобки и кавычки в моём примере — там одномерный JSON массив со строкой внутри.
У тебя — просто строка со скобочками, которая вовсе не раскодируется как JSON. Верный код:
И если я ничего не путаю, то при вызове из PHP можно вообще не париться с JSON, а указывать просто массив вот так:
У тебя — просто строка со скобочками, которая вовсе не раскодируется как JSON. Верный код:
$where = "TVfo LIKE '%Южный%' AND (TVclient_activity LIKE '%Физ.охрана%' OR TVclient_activity LIKE '%Пультовая охрана%'";
$output .= $modx->runSnippet('pdoResources',array(
'includeTVs' => $includeTVs,
'where' => $modx->toJSON(array($where)),
));
И если я ничего не путаю, то при вызове из PHP можно вообще не париться с JSON, а указывать просто массив вот так:
$output .= $modx->runSnippet('pdoResources',array(
'includeTVs' => $includeTVs,
'where' => array($where),
));
Но не факт — нужно проверять. 'where' => $modx->toJSON(array($where)),
Это способ работает. Но в целом не удалось получить то что надо. Ситуация у меня следующая. С помощью getResources, описанным в посте способом, я получаю список объектов. Он выводится у меня постранично. На против каждого объекта есть чекбокс. Ещё есть форма-фильтр. Мне нужно отметить чекбоксы всех записей, которые соответствуют фильтру, а их на данный момент может быть до 2500.
Изначально я сделал всё на getResources. Всё работает. Теперь же решил ускорить работу и для выделения чекбоксов решил использовать ajax с pdoResources.
Теперь я могу визуально наблюдать разницу между getResources и pdoResources. Есть ряд записей, которые pdoResources мне не возвращает, хотя они соответствуют условию фильтра, и тот же getResources мне их отдаёт
хотя они соответствуют условию фильтра,Если речь о значении ТВ «по умолчанию» — то их нет в БД физически, так что pdoResources их не выберет.
А в остальном должно всё работать.
Спасибо!
Проверил, действительно у неотмеченных записей проставлены значения по умолчанию. Буду искать способ как автоматом проставить все записи по умолчанию
Проверил, действительно у неотмеченных записей проставлены значения по умолчанию. Буду искать способ как автоматом проставить все записи по умолчанию
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.