Когда-то давным-давно я писал о том, как организовал примитивный парсинг для "умного" поиска по тегам.
С тех пор много воды утекло. Во-первых - я переписал сайт с рельс на ноду, а во-вторых я научился-таки нормально общаться с СУБД.
И так, вот как
примерно сейчас на
этом сайте происходит выборка по нескольким тегам:
view: function(req, res) {
var tags_plus = []; // тут будут лежать теги, по которым ищем
var tags_minus = []; // а здесь те - по которым исключаем
var tmp1 = req.params.id.replace("'", "''"); // не самое хорошее решение для предотвращения инъекций
tmp1 = tmp1.split('+');
var tmp2 = [];
var i, j;
var s_tags_plus;
var s_tags_minus;
var where = [];
for (i = 0; i < tmp1.length; i = i + 1) {
tmp2 = tmp1[i].split('-');
tags_plus.push(tmp2[0].toLowerCase());
for (j = 1; j < tmp2.length; j = j + 1) {
tags_minus.push(tmp2[j].toLowerCase());
}
}
tags_plus = tags_plus.uniq(); // убираем повторения, в идеале - регистронезависимо
tags_minus = tags_minus.uniq(); // в массиве теперь каждый элемент уникален - дублей нет
if (tags_plus.length > 0) {
s_tags_plus = "'" + tags_plus.join("','") + "'";
// ниже имеется два способа обработки знака сложения. Один из них надо будет повесить на символ "|"
// where.push(' p.id_post in ( select v.id_post from v_tags_by_post v where lower(v.tag_name) in (' + s_tags_plus + '))');
where.push( ' ( ' + (tags_plus.map(function(tname){return " exists ( select 1 from v_tags_by_post v where p.id_post=v.id_post and lower(v.tag_name)=lower('" + tname + "'))"}).join(' AND ')) + ' ) ' );
}
if (tags_minus.length > 0) {
s_tags_minus = "'" + tags_minus.join("','") + "'";
where.push(' p.id_post NOT in ( select v.id_post from v_tags_by_post v where lower(v.tag_name) in (' + s_tags_minus + '))');
}
db.query("select p.* from v_posts_by_blog p where " + where.join(' AND ') + " order by post_rate_damped desc, post_rate desc, post_created_at desc", function(err, rez) {
if(rez.rows.length == 1) res.redirect('/'+rez.rows[0].blog_permalink+'/'+rez.rows[0].id_post); // если найден один-единственный пост - переходим сразу к нему
else res.render('tags/view', {data: rez.rows});
});
}
Примерно, - потому что в действительности происходит разбиение по страницам, выборка из некоторых попутных таблиц сопутствующей информации.
Да и вообще развиваюсь =)) добалвяю обработку символа "|"
Но принцип именно такой - т.е. в отличие от ранее существовавшего "детского" варианта - тут я формирую необходимый запрос.
Что из себя представляют используемые представления (view) - думаю понятно из их названий и без дополнительных пояснений.
Полина Ростова