使用新标签填充自动完成列表

Populating Autocomplete list with new tags

我正在使用 Lucee 5.x 和 Maria DB (MySQL)。

我有一个用户提供的逗号分隔列表。我需要查询数据库,如果该项目不在数据库中,我需要添加它。

用户提供的列表
green blue purple white

数据库项目
black white red blue pink orange lime

预计数据库列表不会增加到 30 多个项目,但最终用户总能找到 'creative' 方式来使用我们提供的工具。

所以使用上面的用户提供的列表,只有 greenpurple 应该添加到数据库中。

我是否将用户提供的列表与数据库项目进行比较,反之亦然?如果用户提供的列表数量超过数据库中的数量(意味着如果用户提交 10 个项目而数据库仅包含 5 个项目),流程会改变吗?我不确定哪个循环是确定哪些项目是新项目的更好方法。需要在 cfscript 中,我正在查看此处概述的循环选项 (https://www.petefreitag.com/cheatsheets/coldfusion/cfscript/)

FOR 循环
FOR IN 循环(数组)
FOR IN 循环(查询)

我尝试了 MySQL 的 NOT IN,但除了新值之外,还剩下现有的数据库值。我知道这应该很简单,我在某个地方把它复杂化了 and/or 我太接近问题了,看不到解决方案。

你可以这样做:

  • 从数据库中获取包含现有项目的列表
  • 附加用户提供的列表
  • 删除重复项
  • 如果添加了项目则更新数据库

<cfscript>

    var userItems = '"green","blue","purple","white"';
    var dbItems = '"black","white","red","blue","pink","orange","lime"';
    var result = ListRemoveDuplicates( ListAppend(dbItems, userItems));

    if (ListLen(result) neq ListLen(dbItems)) {
      // update db
    }

</cfscript>

Update (only new items)

<cfscript>

    var userItems = '"green","blue","purple","white"';
    var dbItems = '"black","white","red","blue","pink","orange","lime"';
    var newItems = '';

    ListEach(userItems, function (item) {
        if (not ListFind(dbItems, item)) {
          newItems = ListAppend(newItems, item);
        }
    })

</cfscript>

trycf.com要点:
(https://trycf.com/gist/f6a44821165338b3c10b7808606979e6/lucee5?theme=monokai)

同样,由于这是数据库可以执行的操作,我会将输入数据提供给数据库,然后让它决定如何处理多个键。我不建议使用 CF 循环遍历您的值以检查它们,然后执行 INSERT。这将需要多次访问数据库,然后在实际上不需要的应用程序服务器上进行处理。

我的建议是使用 MariaDB 的 INSERT....ON DUPLICATE KEY UPDATE... 语法。这还需要您尝试插入的任何字段实际上都具有 UNIQUE 约束。如果没有该约束,那么您的数据库本身并不关心您是否有重复数据,何时会导致其自身的一系列问题。

对于数据库,我们有

CREATE TABLE t1 (mycolor varchar(50)
  , CONSTRAINT constraint_mycolor UNIQUE (mycolor)
) ; 

INSERT INTO t1(mycolor)
VALUES ('black'),('white'),('red'),('blue'),('pink'),('orange'),('lime') 
;

ColdFusion 是:

<cfscript>

myInputValues = "green,blue,purple,white" ;

myQueryValues = "" ;

function sanitizeValue ( String inVal required ) {
    // do sanitization stuff here
    var sanitizedInVal = arguments.inVal ;
    return sanitizedInVal ;
}

myQueryValues = myInputValues.listMap( 
    function(i) {
        return "('" & sanitizeValue(i) & "')" ;
    } 
) ;

// This will take parameterization out of the cfquery tag and
    preform sanitization and validation before building the 
    query string.

myQuery = new query();
myQuery.name = "myQuery";
myQuery.setDataSource("dsn");

sqlString = "INSERT INTO t1(mycolor) VALUES " 
    & myQueryValues 
    & " ON DUPLICATE KEY UPDATE mycolor=mycolor;" 
;

myQuery.setSQL(sqlString);
myQueryResult = myQuery.execute().getResult();

</cfscript>

首先,建立您的输入值 (myInputValues)。您需要对它们进行验证和清理,以防止恶意内容进入您的数据库。我创建了一个 sanitizeValue 函数作为清理和验证操作的占位符。

myQueryValues 将成为我们将用于插入数据库的正确格式的值的字符串列表。

然后我们就建立一个new query(),在sqlString中使用myQueryValues来得到我们的查询。同样,由于我们正在为 INSERT 的多个值构建一个字符串,我认为没有办法为那些 VALUES 用户 queryparam。但是由于我们之前清理了我们的字符串,所以它应该可以完成 cfqueryparam 所做的大部分工作。

我们使用 MariaDB 的 INSERT INTO .... ON DUPLICATE KEY UPDATE ... 语法来仅插入唯一值。同样,这要求数据库本身有一个约束,以防止在我们插入的任何列中出现重复。

演示:https://dbfiddle.uk/?rdbms=mariadb_10.2&fiddle=4308da3addb9135e49eeee451c6e9e58

这应该可以完成您想要做的事情,而不会过多地破坏您的数据库。我没有设置要测试的 Lucee 或 MariaDB 服务器,因此您必须尝试一下,看看它的性能如何。我不知道您的数据库有多大或将有多大,但这应该仍然可以很快查询。