2016-11-08 10 views
1

一意のURL-frinedlyルート、 ループは、私は、この構造でmariadbのテーブルを持っている

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

は、私は、ユーザーfriendy URLを取得するために route列を使用、など http://www.examle.com/this-is-the-route-of-an-item

生成しますユーザーは空白や違法な文字を除いて、新しいアイテムを作成します。新しいアイテム用に選択されたルートが使用されているケースを「キャッチ」し、有効なルートを生成したいと思います。例えば

route-of-an-itemが既に使用中である場合、iはroute-of-an-item-a、またはroute-of-an-item-bへのフォールバックであろうが、等

ナイーブ溶液(擬似コードの一種)は、例えば、ループ内のDBを照会することができる:

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

finalRoute = route + '-' + additionalChars; 

これは、何度もデータベースにクエリすることを伴うので、私は別の解決策を考えました。

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; 

このような問題にアプローチする方法はありますか?

私は、2番目のソリューションの方が優れていると修正しましたか?

2番目のソリューションを使用する場合は、フルテキストインデックスを追加する必要がありますか?

+0

の終わりにapears以来

とフルテキストインデックスは必要ありませんか? –

+1

あなたはそれを挿入し、dbの一意のインデックス例外をキャッチしようとすることができます。変更してもう一度やり直してください。あなたが成功に達するまで繰り返す。 – ojf

+0

@TimBiegeleisen定義されていません。これはちょうどpesudoコードです。 – MoLow

答えて

0

OK::

あなたの擬似コードでは、これは次のようになります。

DBアクセス

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(''); 
} 

私は1つの選択クエリと1つのインセットクエリで終わり、ノードの側での衝突を防ぎます。 %のみ `nextAdditionalChars`が定義されているlike operater

1

ルート降順でクエリをソートし、1つのアイテムのみを取得してチェックすることができます。場合には誰もがこの問題に直面し、私は解決策2を使用して終了同僚と相談した後、ここにコード(Node.jsの)があるので、

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'を追加すると、3人目のユーザが 'route-name'を追加したいと仮定できます。' route-name ' -a'を使って衝突を防ぎますが、あなたの答えの質問は 'route-name-etc'についてだけ教えてくれるので、まだクラッシュする可能性があります。 – MoLow

+0

よろしくお願いします。ルート名の末尾にIDを追加するだけで、一意のURLを生成することができます。このようにして、何もチェックする必要はありません。 –

+0

私はURLのためのIDを私に直接与えることができました。私のIDは36文字の長さのUUIDです。 – MoLow

関連する問題