pdoFetch поиск в TV-полях с разделителем ||
Наверняка много кто использовал в своей практике TV-поля типа «Список» (множественный, одиночный, не важно) или «Тег». Здесь важно именно то, в каком виде в базе данных хранятся данные таких полей, ведь они сохраняют множественные значения. А хранят они их одной общей строкой в той же самой таблице ТВшек (естественно, по одной записи на один документ). К примеру, если мы отметили три значения 100, 1005, 10, в БД это запишется 100||1005||10. И здесь возникает вопрос как потом выполнить поиск по таким полям? Простой LIKE здесь не поможет, так как LIKE %100%, к примеру, найдет и '100||1000' и '1001||1005'. Данного вопроса мы уже касались здесь и подобный вопрос опять возник здесь.
В подобных ситуациях нам в помощь SQL-метод FIND_IN_SET(). Он как раз и позволяет выполнять поиск с точным вхождениям в строках с разделителем-запятой. Правда, в нашем случае придется выполнить еще одну операцию — замену разделителя || на запятую. В этом нам поможет SQL-метод REPLACE.
Посмотрев код pdoFetch, на сколько я понял, через параметр tvFilters этого сделать нельзя, так как у него там ограниченный набор элементов сравнения (по умолчанию LIKE). А здесь нужен FIND_IN_SET(). Мы этот вопрос разбирали еще здесь. Здесь нам в помощь параметр where. В него можно передавать дополнительные условия поиска массивом или JSON-строкой.
Примерный запрос выглядит так:
1 = 1 необходимо, чтобы обойти ограничения xPDO, который имеет определенный набор разрешенных методов. Если мы этого не сделаем, то получим примерно такую ошибку: Error parsing condition with key 0: FIND_IN_SET(…
В подобных ситуациях нам в помощь SQL-метод FIND_IN_SET(). Он как раз и позволяет выполнять поиск с точным вхождениям в строках с разделителем-запятой. Правда, в нашем случае придется выполнить еще одну операцию — замену разделителя || на запятую. В этом нам поможет SQL-метод REPLACE.
Посмотрев код pdoFetch, на сколько я понял, через параметр tvFilters этого сделать нельзя, так как у него там ограниченный набор элементов сравнения (по умолчанию LIKE). А здесь нужен FIND_IN_SET(). Мы этот вопрос разбирали еще здесь. Здесь нам в помощь параметр where. В него можно передавать дополнительные условия поиска массивом или JSON-строкой.
Примерный запрос выглядит так:
[[!pdoPage?
&limit=`18`
&includeTVs=`categories`
&where=`["1 = 1 AND FIND_IN_SET('[[*id]]', replace(categories, '||', ','))"]`
]]
В данном случае replace(categories, '||', ',') заменит все разделители || на, (зпт), что позволит искать четкие вхождения в составной строке методом FIND_IN_SET(). 1 = 1 необходимо, чтобы обойти ограничения xPDO, который имеет определенный набор разрешенных методов. Если мы этого не сделаем, то получим примерно такую ошибку: Error parsing condition with key 0: FIND_IN_SET(…
Комментарии: 19
Отличный способ!
А &tvFilters нужен исключительно для совместимости с getResources. Никому не рекомендую его использовать.
А &tvFilters нужен исключительно для совместимости с getResources. Никому не рекомендую его использовать.
Рад, что не напрасно писал :)
Николай, очень нужная информация, долго искал, но с выборкой из migx не работает.
У меня запрос такой:
Третий день бьюсь. Испробовал кучу вариантов, но нет.
У меня запрос такой:
[[!pdoPage?
&element=`getImageList`
&tvname=`catalogs_pdf`
&tpl=`tpl_catalogs_pdf`
&docid=`7`
&includeTVs=`id_pages`
&where=`["1 = 1 AND FIND_IN_SET('[[*id]]', replace(id_pages, '||', ','))"]`
]]
id_pages представляет собой простую строку, куда я вручную прописываю id ресурсов (пример — 5||20||13).Третий день бьюсь. Испробовал кучу вариантов, но нет.
Не пользуюсь getImageList. Но уверен на 98%, он формирует SQL-запросы стандартным xPDO-механизмом, а не как у Василия. И на сколько я могу судить по документации, getImageList не умеет принимать параметр includeTVs и ему в принципе пофиг на &includeTVs=`id_pages`. Таким образом колонки id_pages в запросе просто не будет. Но повторюсь, могу ошибаться, так как ни с pdoPage, ни с getImageList не работаю. Может кто другой подскажет.
Да, &includeTVs я на всякий случай). Спасибо за оперативный ответ.
Не за что
getImageList принимает и выводит исключительно TV.
Как вариант сделать следующее:
Как вариант сделать следующее:
[[!getImageList?
&tvname=`catalogs_pdf`
&tpl=`@CODE:[[+item:replace=`||==,`]]` // Вроде бы так. - заменяем ваш разделитель на зпт.
&docid=`7`
&toPlaceholder=`asdasd`
]]
[[!pdoPage?
&parents=`0` // или ваша вложенность
&resources=`[[!+asdasd]]`
&element=`pdoResources`
]]
Надеюсь смысл понятен. :) Синтаксис не проверял. Показал принцип.
Alex, если не трудно, разжуйте поподробнее.
Я в свою очередь тоже, т.к. боюсь меня не правильно поняли.
В базе Migx хранятся каталоги с описанием, картинкой и т.д.
Помимо родного ресурса эти каталоги нужно вывести и на многих других.
Соответственно, на этом этапе нужна выборка определенных каталогов для определенного ресурса.
Задачу пытался решить так:
создал в Migx базе еще одно поле, где вручную указываю id ресурсов (пример — 5||20||13).
А на странице определенного ресурса уже вызов сниппета, который написал выше, только рабочий вызов where пока такой:
Я в свою очередь тоже, т.к. боюсь меня не правильно поняли.
В базе Migx хранятся каталоги с описанием, картинкой и т.д.
Помимо родного ресурса эти каталоги нужно вывести и на многих других.
Соответственно, на этом этапе нужна выборка определенных каталогов для определенного ресурса.
Задачу пытался решить так:
создал в Migx базе еще одно поле, где вручную указываю id ресурсов (пример — 5||20||13).
А на странице определенного ресурса уже вызов сниппета, который написал выше, только рабочий вызов where пока такой:
&where=`{"id_pages:=":"[[*id]]"}`
Проблема в том, что в id_pages иногда приходится вставлять несколько id, тогда не работает.
Так, наверное тут нужно сначала разобраться со структурой.
У вас Есть Родитель, У него Ресурсы, у ресурсов TV (MIGX) с Описаниями, картинками? MIGX настроен обычным способом.
Вам нужно вывести на любой странице определенные ресурсы, которые вы указываете в другом родителе через TV поле?
Скиньте снипет ваш который рабочий, т.к. сложно понять что сейчас у вас не так. :)
У вас Есть Родитель, У него Ресурсы, у ресурсов TV (MIGX) с Описаниями, картинками? MIGX настроен обычным способом.
Вам нужно вывести на любой странице определенные ресурсы, которые вы указываете в другом родителе через TV поле?
Скиньте снипет ваш который рабочий, т.к. сложно понять что сейчас у вас не так. :)
У меня есть ресурс — страница со всеми каталогами. Все каталоги собсна хранятся в Migx базе. Моя задача выводить некоторые каталоги на других ресурсах помимо родного. Для этого я создал доп поле в этой же базе migx, куда указываю нужные id страницы для каждого каталога.
Вызов сниппета на других ресурсах такой:
Вызов сниппета на других ресурсах такой:
[[!pdoPage?
&element=`getImageList`
&tvname=`catalogs_pdf`
&tpl=`tpl_catalogs_pdf`
&docid=`7`
&where=`{"id_pages:in":"[[*id]]"}`
]]
Но он работает только если в этом поле указан 1 id. А надо бы, чтобы сниппет мог отыскать id необходимого ресурса среди нескольких значений.
Спасибо всем, кто отозвался. Проблема решилась банально и просто, как и должно было быть. Только сколько пришлось попотеть…
Кому будет тоже нужно:
В поле id_pages, id ресурсов нужно прописать так, чтобы их однозначно можно было определить.
Например, так:
2#3#
Условие where переписать на следующее:
Кому будет тоже нужно:
В поле id_pages, id ресурсов нужно прописать так, чтобы их однозначно можно было определить.
Например, так:
2#3#
Условие where переписать на следующее:
&where=`{"id_pages:contains":"[[*id]]#"}`
в итоге рабочий вызов будет таким:[[!pdoPage?
&element=`getImageList`
&tvname=`catalogs_pdf`
&tpl=`tpl_catalogs_pdf`
&docid=`7`
&where=`{"id_pages:contains":"[[*id]]#"}`
]]
Подсказали тут: itchief.ru/lessons/modx-revo/modx-migx
Здравствуйте, подскажите пожалуйста как применить такой запрос [«1 = 1 AND FIND_IN_SET('[[*id]]', replace(categories, '||', ','))»] в своем сниппете?
Пробовал так:
Пробовал так:
$param['parent'] = 6;
$param['where'] = ["1 = 1 AND FIND_IN_SET('Москва', from_city)"];
$params = array_diff($param, array(''));
$q = $modx->newQuery('modResource', $params);
$q->limit(1000);
$q->prepare();
$q->stmt->execute();
$res = $q->stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($res as $v) {
echo $v['modResource_pagetitle'];
}
Но результата нет
AND FIND_IN_SET('[[*id]]', работать не будет, так как это MODX-плейсхолдер, а не конечное значение. Формируя таким образом запрос, вы в БД ищете не id текущего документа, а конкретно строчное значение '[[*id]]'.
Надо так:
[«1 = 1 AND FIND_IN_SET({$modx->resource->id}, replace(categories, '||', ','))»]
или
[«1 = 1 AND FIND_IN_SET({$modx->getPlaceholder('id')}, replace(categories, '||', ','))»]
Это если в сниппете. Если вы в феном или еще где-то пишете, может чуть отличаться синтаксис, но смысл, думаю, вы уловили.
Надо так:
[«1 = 1 AND FIND_IN_SET({$modx->resource->id}, replace(categories, '||', ','))»]
или
[«1 = 1 AND FIND_IN_SET({$modx->getPlaceholder('id')}, replace(categories, '||', ','))»]
Это если в сниппете. Если вы в феном или еще где-то пишете, может чуть отличаться синтаксис, но смысл, думаю, вы уловили.
Вместо
"1 = 1 AND FIND_IN_SET('Москва', from_city)"
можно (правильней) написать"FIND_IN_SET('Москва', from_city) > 0"
1 = 1 AND вводилось для обхода проверки xPDO на метод FIND_IN_SET (раньше он его не знал и обламывал, не знаю как он сейчас на него реагирует. Если положительно, то можно 1=1 и не писать).
можно (правильней) написатьТогда уж и вовсе «FIND_IN_SET('Москва', from_city)», так как результат этой функции проверяется на true|false.
«FIND_IN_SET('Москва', from_city) > 0»
скажите правильно ли я понял, должны быть так?
$param['where'] = ["FIND_IN_SET('Москва', from_city) > 0"];
А как переписать это условие на fenom? Я всю голову сломал, пытаясь это сделать.
Я не знаю как правильней всего в феном, но можете там использовать объект $_modx. Вот изучите вот эти примеры: modxclub.ru/topics/eshhe-odin-primer-slozhnyix-sql-zaprosov-1922.html
Только там нативный объект $modx, в феноме вам надо использовать $_modx, вроде должно работать.
Только там нативный объект $modx, в феноме вам надо использовать $_modx, вроде должно работать.
Здравствуйте!
Подскажите, у меня вот такая конструкция:
Пытаюсь вывести по вашему примеру:
Извините, я не спец…
Спасибо!
Подскажите, у меня вот такая конструкция:
'where' => '{"portfolio_name:LIKE":"%[[*menutitle]]%","video.value:!=":1 }'
Я вывожу видео из портфолио в товарах проверяя совпадения по названию товара. Но как и ожидалось, выводятся видео с похожими названиями. К примеру: — Калуга||ЛугаПытаюсь вывести по вашему примеру:
'where' => ["1 = 1 AND FIND_IN_SET('[[*portfolio_name]]', replace(menutitle, '||', ','))"]
Но не пойму, как сделать ещё одни запрос «video.value:!=»:1Извините, я не спец…
Спасибо!
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.