如何将标签映射到标签同义词?

Ang*_*oob 5 javascript mysql sql node.js node-mysql

我正在建立一个用户将标签与帖子关联起来的系统,与SO不同.我有一个懒得实现标签同义词的地方.

这里我有一个名为Tags的表:

| TagName    |
|------------|
| Python     |
| JavaScript |
| Node       |
Run Code Online (Sandbox Code Playgroud)

我有另一个名为TagSynonyms:

| SynonymId | SourceTagName | TargetTagName |
|-----------|---------------|---------------|
| 1         | Py            | Python        |
| 2         | Python2       | Python        |
Run Code Online (Sandbox Code Playgroud)

服务器使用Node实现,用户以逗号分隔的字符串输入一些标签:

var input = 'Py,Flask'
var tags = request.tags.split(',');
Run Code Online (Sandbox Code Playgroud)

在这种情况下,用户输入了标签Py,根据TagSynonyms表,它应该映射到标签Python.第二个标签,Flask没有同义词,应该保持不变.

我设法使用命令式代码实现此功能:

tags.forEach(function (tag) {
  connection.query('SELECT TargetTagName FROM TagSynonyms WHERE SourceTagName = ?', tag, function(err, rows) {
    if (rows.length !== 0) {
      console.log(rows[0].TargetTagName);
    } else {
      console.log(tag);
    }
  });
});
Run Code Online (Sandbox Code Playgroud)

这里是用户输入

['Py','Flask'] 
Run Code Online (Sandbox Code Playgroud)

得到以下输出

Python
Flask
Run Code Online (Sandbox Code Playgroud)

我想要做的是,将这个逻辑推迟到数据库引擎,因为我认为使用循环是代码气味.我还认为数据库引擎会更高效.执行此操作的适当查询是什么?

Aar*_*lla 3

您需要一个UNION和一个连接:

  select TagName
    from Tags
    where TagName in (?,?,?,...)
union
  select TagName
    from Tags
    join TagSynonyms
      on Tags.TagName = TagSynonyms.TargetTagName
    where TagSynonyms.SourceTagName in (?,?,?,...)
Run Code Online (Sandbox Code Playgroud)

请注意,这union可能会很慢,因为它会尝试删除重复项。如果您属于这种情况,请使用union all并删除应用程序代码中的重复项。

(?,?,?,...)代表输入值列表;检查数据库驱动程序文档,了解避免 SQL 注入所需使用的确切语法。

更新: Node 中的实现如下所示:

var query = 
'SELECT TagName \
FROM Tags \
WHERE TagName IN (?) \
UNION \
SELECT TagName \
FROM Tags \
JOIN TagSynonyms \
  ON Tags.TagName = TagSynonyms.TargetTagName \
WHERE TagSynonyms.SourceTagName IN (?)'

connection.query(query, [tags, tags], function(err, rows) {
  tags = rows.map(function(row) { 
    return row.TagName
  });
});
Run Code Online (Sandbox Code Playgroud)