如何使用RediSearch筛选子数组中子对象同时匹配双属性的条目
RedisJSON + RediSearch 子数组对象多属性联合查询问题解决
你的问题根源在于当前索引的设计:当使用$.childObjects[*].field1和$.childObjects[*].field2创建TAG字段时,RediSearch会将数组中所有子对象的field1值收集为一个集合,field2同理。执行@field1:{Foo} @field2:{Bar}查询时,只要文档的field1集合包含Foo且field2集合包含Bar就会匹配——不管这两个值是否来自同一个子对象,所以id=2的文档会被误返回。
以下是两种可行的修正方案:
方案1:创建复合TAG字段(推荐,性能最优)
重新构建索引,将每个子对象的field1和field2组合成一个单独的TAG字段,确保两个条件绑定到同一个子对象:
- 先删除旧索引:
FT.DROPINDEX cities_idx
- 创建包含复合字段的新索引:
FT.CREATE cities_idx ON JSON PREFIX 1 search:cities: SCHEMA $.childObjects[*].field1 AS field1 TAG $.childObjects[*].field2 AS field2 TAG $.childObjects[*].field1 + ":" + $.childObjects[*].field2 AS combined_field TAG
(注意:如果你的实际JSON字段名是fieldOne/fieldTwo(和你索引命令里一致),请替换路径中的field1/field2)
- 使用复合字段执行查询:
FT.SEARCH cities_idx @combined_field:{Foo:Bar}
这个查询只会匹配存在子对象同时满足field1="Foo"且field2="Bar"的文档,即仅返回id=1的结果。
方案2:用AGGREGATE命令实时过滤(无需修改索引)
如果不想修改现有索引,可以用FT.AGGREGATE结合数组过滤函数,直接检查文档中是否存在符合条件的子对象:
FT.AGGREGATE cities_idx * LOAD 1 $.childObjects FILTER EXISTS(ARRAY_FILTER(@childObjects, "x -> x.field1 == 'Foo' && x.field2 == 'Bar'"))
LOAD 1 $.childObjects:加载文档中的childObjects数组ARRAY_FILTER:遍历数组,筛选出同时满足两个条件的元素EXISTS:判断筛选结果是否非空,非空则保留该文档
这个方案适合临时查询或条件多变的场景,但性能略低于方案1,因为需要加载数组并执行过滤逻辑。
内容的提问来源于stack exchange,提问作者LunchBaron
相关产品推荐
相关产品推荐

