如何在Dexie查询中对同一属性设置多个where子句?
Dexie 数组字段多条件索引查询实现
问题场景
有一个已建立索引的字符串数组字段,需要筛选出同时满足以下两个条件的记录:
- 数组不包含字符串
a - 数组包含字符串
b
现有单条件查询代码仅能实现不包含a的筛选,因为notEqual()返回的是Collection类型,不支持直接链式调用仅作用于Table对象的where()方法:
db.table.where('array').notEqual('String(a)').toArray()
已尝试的全表过滤方案性能较差,希望得到更规范高效的实现:
db.table.toCollection(function (e) { return (!e.array.includes('String(a)') && e.array.includes('String(b)')) }).toArray()
实现方案
方案1:索引命中+Collection过滤(性能最优)
Dexie的Collection对象提供了filter()方法支持追加自定义过滤逻辑,优先把能大幅缩小结果范围的正向匹配条件放在前面走索引,再在小结果集上做内存过滤,性能远高于全表扫描:
// 先走multiEntry索引命中所有包含b的记录,再在结果中排除包含a的项 const result = await db.table .where('array') .equals('String(b)') .filter(item => !item.array.includes('String(a)')) .toArray()
注意:不要把
notEqual()作为首个查询条件,该方法会扫描索引中除目标值外的所有条目,性能极差。
方案2:and链式过滤(Dexie 3.0+版本适用)
3.0及以上版本的Dexie支持在Collection上直接调用and()方法追加过滤条件,写法更简洁,底层逻辑和方案1一致:
const result = await db.table .where('array').equals('String(b)') .and(item => !item.array.includes('String(a)')) .toArray()
配置注意事项
数组字段的索引需要显式开启multiEntry模式才能让equals()匹配数组内元素的逻辑生效,建表时需要在数组字段前加*标识:
const db = new Dexie('yourDB') db.version(1).stores({ table: 'id, *array' // *前缀代表数组字段启用multiEntry索引 })
你之前写的给toCollection()直接传过滤函数的写法属于全表扫描,数据量超过千条后性能会明显下降,不推荐在生产环境使用。
内容的提问来源于stack exchange,提问作者skns
相关产品推荐
相关产品推荐

