含括号的Typesense查询出现404错误求助
解决Typesense复杂过滤查询的404错误
环境配置
- Ionic 5
- Angular 12
- NodeJS 14
- Typesense 1.4.1
报错信息
ERROR Error: Uncaught (in promise): u: Request failed with HTTP code 404 | Server said: Could not find a filter field named `(startTime` in the schema.
问题代码
构建查询的核心代码如下:
searchAtlistedProEvents(asi: AtlistedSearchInfo) { if (asi.displayName === "") { asi.displayName = "*" } let searchParameters: SearchParams = { q: asi.displayName, query_by: "displayName", filter_by: this.buildFilterByString(asi), sort_by: this.buildSortByString(asi) } const typesenseClient = new typesense.Client({ nodes: [{ host: "my-server.a1.typesense.net", port: 443, protocol: "https", }], apiKey: this.TYPESENSE_SEARCH_PUBLIC_API_KEY, connectionTimeoutSeconds: 2, }); return typesenseClient.collections("atlistedProEventNewIndex").documents().search(searchParameters).then((doc) => { console.log("TYPSENSE RESPONSE HERE doc", doc); return doc; }) } buildFilterByString(asi: AtlistedSearchInfo) { let days = asi.days.map((day: Date) => { const start = new Date(day.valueOf()); const end = new Date(day.valueOf()); start.setHours(asi.startTimeOfDay.getHours(), asi.startTimeOfDay.getMinutes()); end.setHours(asi.endTimeOfDay.getHours(), asi.endTimeOfDay.getMinutes()); const fbStart = Number(firebase.firestore.Timestamp.fromDate(start).seconds); const fbEnd = Number(firebase.firestore.Timestamp.fromDate(end).seconds); return [fbStart, fbEnd]; }); let filterByString = ""; for (let i = 0; i < days.length; i++) { filterByString += "(startTime:<=" + days[i][0] + " && " + "stopTime:">=" + days[i][1] + ") "; if (i < days.length - 1) { filterByString += " || "; } } filterByString += " && eventRate:<=" + asi.eventRate + " && remainingSlots:">=" + asi.remainingSlots + " && "; filterByString += "location:(" + asi.location[0] + ", " + asi.location[1] + ", " + asi.locationRadius + "mi)"; console.log("THis is final filterByString buildFilterByString", filterByString); return filterByString; }
现象说明
- 去掉括号仅查询单个日期时,请求可以成功;
- 添加括号构建多条件组的复杂查询时,触发上述404错误;
- 官方说明Typesense支持嵌套过滤表达式,但实际生成的过滤字符串存在格式问题。
生成的错误格式filter_by字符串:
(startTime:<="1666972800 && stopTime:">="1667001600) && eventRate:<="55 && remainingSlots:">="1 && location:(32.4059605, -99.4936912, 25mi)
解决方案
问题出在字符串拼接时的引号位置错误:每个字段的取值引号未正确闭合,导致Typesense解析器误将(startTime当成字段名。
修正buildFilterByString函数中的字符串拼接逻辑,使用模板字符串确保引号正确闭合:
buildFilterByString(asi: AtlistedSearchInfo) { let days = asi.days.map((day: Date) => { const start = new Date(day.valueOf()); const end = new Date(day.valueOf()); start.setHours(asi.startTimeOfDay.getHours(), asi.startTimeOfDay.getMinutes()); end.setHours(asi.endTimeOfDay.getHours(), asi.endTimeOfDay.getMinutes()); const fbStart = Number(firebase.firestore.Timestamp.fromDate(start).seconds); const fbEnd = Number(firebase.firestore.Timestamp.fromDate(end).seconds); return [fbStart, fbEnd]; }); let filterByString = ""; for (let i = 0; i < days.length; i++) { // 用模板字符串确保引号正确闭合 filterByString += `(startTime:<="${days[i][0]}" && stopTime:>="${days[i][1]}")`; if (i < days.length - 1) { filterByString += " || "; } } // 修正后续条件的引号位置 filterByString += ` && eventRate:<="${asi.eventRate}" && remainingSlots:>="${asi.remainingSlots}" && `; filterByString += `location:(${asi.location[0]}, ${asi.location[1]}, ${asi.locationRadius}mi)`; console.log("THis is final filterByString buildFilterByString", filterByString); return filterByString; }
修正后生成的正确格式filter_by字符串:
(startTime:<="1666972800" && stopTime:>="1667001600") && eventRate:<="55" && remainingSlots:>="1" && location:(32.4059605, -99.4936912, 25mi)
这样Typesense就能正确解析过滤条件,不会再出现字段识别错误。
内容的提问来源于stack exchange,提问作者Willem Ghijsen
相关产品推荐
相关产品推荐

