如何使用Typeahead和Bloodhound一次使用多个数据集?

时间:2017-04-26 13:23:37

标签: javascript json typeahead.js bloodhound

我正在尝试使用Typeahead / Bloodhound进行建议和搜索。为简单起见,我们假设我有两种类型的模型对象 - 国家/地区城市

public class Country
{
    public string Name { get; set; }
}

(服务器端在ASP.NET中,但这与问题无关)。

城市几乎与国家相同,但名称不同。

无论如何,在造型之前,我希望最终结果看起来像这样:

bloodhound multiple datasets

(如果不是很明显,我在文本框中写了“AL”,剩下的字母构成了第一个建议)

我可以通过使用多个Bloodhounds轻松实现这一目标:

var countries = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    limit: 5,
    remote: {
        url: 'http://localhost:5000/api/countries/%QUERY',
        wildcard: '%QUERY'
    }
});

var cities = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    limit: 5,
    remote: {
        url: 'http://localhost:5000/api/cities/%QUERY',
        wildcard: '%QUERY'
    }
});

和多个要输入的输入对象:

$('#remote .typeahead').typeahead(null,
    {
        name: 'countries',
        display: 'name',
        source: countries,
        templates: {
            empty: [
                '<div class="empty-message">',
                'unable to find any countries that match the current query',
                '</div>'
            ].join('\n'),
            suggestion: Handlebars.compile('<div><strong>{{name}}</strong></div>'),
            header: '<h2>Countries</h2>'
        }

    },
    {
        name: 'cities',
        display: 'name',
        source: cities,
        templates: {
            empty: [
                '<div class="empty-message">',
                'unable to find any cities that match the current query',
                '</div>'
            ].join('\n'),
            suggestion: Handlebars.compile('<div><strong>{{name}}</strong></div>'),
            header: '<h2>Cities</h2>'
        }

    });

然而,在我的真实场景中,我有大约10个数据集。创建10个单独的查询,结合JSON序列化/反序列化可能会在现场终止我的服务器,尤其是对于多个用户。

我更喜欢的是复合DTO:

public class CompositeSearchResult
{
    public List<Country> Countries { get; set; }
    public List<City> Cities { get; set; }
    //... and many others
}

...虽然以某种方式使用Bloodhound处理客户端上的复杂对象。这可能吗?

1 个答案:

答案 0 :(得分:2)

我做到了!

首先我发现,Bloodhound缓存是聪明的 - 所以如果搜索查询已经由它进行,它将不再使用网络 - 而是会在缓存中查找。

因此,这意味着如果两个数据集的URL相同,则查询仅在服务器上执行一次,然后结果集将被缓存并被所有猎犬使用。

回到简单的Countries + Cities示例,它应该如下所示:

DROP TABLE IF EXISTS transactions;

CREATE TABLE transactions
(transaction_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,book_id INT NOT NULL
,transaction_status VARCHAR(12) NOT NULL 
,transaction_date DATE NOT NULL
);

INSERT INTO transactions VALUES
(1,233,'SUCCESS','2017-04-05'),
(2,145,'FAILED','2017-04-10'),
(3,233,'FAILED','2017-04-05'),
(4,233,'SUCCESS','2017-04-05');

SELECT book_id
     , SUM(CASE WHEN transaction_status = 'success' THEN 1 ELSE 0 END)/COUNT(*) success_rate 
  FROM transactions 
 GROUP 
    BY book_id
+---------+--------------+
| book_id | success_rate |
+---------+--------------+
|     145 |       0.0000 |
|     233 |       0.6667 |
+---------+--------------+

两种情况的唯一区别是远程设置中的“转换”功能。

然后,通过使用问题中完全相同的CompositeSearch对象,我可以一次检索两个数据集(基本上与屏幕截图中相同)而不是2 - 通过浏览器的“网络”选项卡确认:)