2016-11-08 4 views
1

У меня есть таблица в MariaDB в этой структуре,петли для генерации уникального URL-frinedly маршрута

CREATE TABLE `items` (
    `id` char(36), `route` varchar(255), `value` text, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `route` (`route`) 
) 

я использую route колонки, чтобы получить пользовательский friendy URL, такие как http://www.examle.com/this-is-the-route-of-an-item

Когда пользователь создает новый элемент, помимо пробелов и недопустимых символов, я хотел бы «поймать» случаи, когда маршрут, выбранный для нового элемента, используется, и создать правильный маршрут.

Например, если route-of-an-item уже используется, я бы возврат к route-of-an-item-a или route-of-an-item-b и т.д.

Наивное решение может быть запрашивая дБ в цикле, например, (вид псевдокоде):

var additionalChars = ""; 
while (db.query("select count * from `items` where `route`='" + route + "-" + additionalChars + "'")) 
    additionalChars = nextAdditionalChars(additionalChars); 

finalRoute = route + '-' + additionalChars; 

Так как это вовлекает частое обращение к db, я думал о другом решении.

var additionalChars = ""; 
var usedRoutes = db.query("select `route` from `items` where `route` like '" + route + "%'"); 
while(usedRoutes.contains(route + '-' + additionalChars)) 
    additionalChars = nextAdditionalChars(additionalChars); 

finalRoute = route + '-' + additionalChars; 

Есть ли лучший способ подойти к этой проблеме?

Правильно ли, что второе решение будет работать лучше?

Если я использую второе решение, должен ли я добавлять полнотекстовый указатель в поле маршрута?

+0

Где 'nextAdditionalChars' определяется? –

+1

Вы можете просто попробовать вставить его и поймать уникальное исключение индекса для db. Затем измените его и повторите попытку. Повторяйте, пока не достигнете успеха. – ojf

+0

@TimBiegeleisen не определен. это всего лишь код pesudo. – MoLow

ответ

0

Ок, после консультации с коллегой, я в конечном итоге с помощью раствора 2, вот код (Node.js), в случае, если кто сталкивается с этой проблемой:

доступа дб

var route = req.body.route || 'noname';  
route = route.replace(/[\s_]/g, '-').toLowerCase().replace(/[^0-9a-z\u0591-\u05F4\u0621-\u064A\-_\s]/g, "").replace(/_+/g, ' ').trim().replace(/[\s_]+/g, '-'); 

var isArabic = (/[\u0621-\u064A]/g).test(route), 
    isHebrew = (/[\u0591-\u05F4]/g).test(route), 
    lang = isArabic ? 'ar' : (isHebrew ? 'he' : 'en'); 

Items.findAll({ where: { route: { $like: route + '%' } }, attributes: ['route'] }) 
    .then((items) => { 
     var routes = _.keyBy(items, 'route'), 
      prefix = ''; 

     while (routes[route + (prefix ? '-' + prefix : '')]) 
      prefix = charactersCount(prefix, lang); 

     Items.create({ route: route + (prefix ? '-' + prefix : ''), value: req.body.value }) 
     .then(function(item){ 
      res.send({ item: _.pick(item, ['id', 'route', 'author_id', 'created_at']) }) 
     }) 
     .catch(function(){ res.sendStatus(500)}); 
    }) 
    .catch(function(){ res.sendStatus(500) }); 

генерируют дополнительные символы

var chars = { 
    ar: { val: "اﻻبتثجحخدذرزسشصضطظعغفقكلمنهةوىي", len: 0 }, 
    he: { val: "אבגדהוזחטיכלמנסעפצקרשת", len: 0 }, 
    en: { val: "abcdefghijklmnopqrstuvwxyz", len: 0 } 
}; 
_.forEach(chars, (c) => { c.len = c.val.length }); 

function charactersCount (current, lang) => { 
    if (!current) return chars[lang].val[0]; 
    lang = lang || 'en'; 
    var curr = current.split(''), 
     len = curr.length, 
     pointer = len, 
     lastIndex; 

    while ((lastIndex = chars[lang].val.indexOf(curr[--pointer]) + 1) >= chars[lang].len) curr[pointer] = chars[lang].val[0]; 
    if (pointer < 0) { curr.unshift(''); pointer++; } 
    curr[pointer] = chars[lang].val[lastIndex]; 

    return curr.join(''); 
} 

поэтому я получаю один запрос на выбор и один запрос вставки и предотвращает столкновения со стороны узла.

и полнотекстовый индекс не требуется, так как % apears только в конце like operater

1

Вы можете отсортировать запрос по маршруту по убыванию и только получить и проверить один элемент. В вашем псевдокоде это будет выглядеть так:

var additionalChars = ""; 
var usedRoutes = db.query("select `route` from `items` where `route` like '" + route + "%' order by `route` desc limit 1"); 
if(usedRoutes.route is already in use) 
    additionalChars = nextAdditionalChars(additionalChars); 

finalRoute = route + '-' + additionalChars; 
+0

Ну, давайте предположим, что пользователь добавляет 'route-name', затем пользователь b, добавляет' route-name-etc', затем третий пользователь хочет добавить 'route-name', я бы хотел преобразовать его в' route-name -a', чтобы предотвратить столкновение, но запрос в вашем ответе только расскажет мне о 'route-name-etc', и я все равно могу столкнуться с столкновением. – MoLow

+0

Хорошо, я понимаю вашу точку зрения. Вы можете просто добавить идентификатор в конце имени маршрута, чтобы создать уникальный URL-адрес. Таким образом, вам вообще ничего не нужно проверять. –

+0

, тогда я мог бы использовать идентификатор для url напрямую. Мой идентификатор - UUID длиной 36 символов. – MoLow

Смежные вопросы