如何在Firestore中获取sport字段含特定关键词的所有文档?
解决Firestore查询sport字段包含特定关键词的问题
你之前修改集合路径为annotations.sport的方式是错误的——annotations是集合的路径,字段过滤不能通过修改路径实现,必须通过Firestore的查询(Query)功能添加筛选条件。以下是具体实现方案:
1. 精确匹配sport字段
如果需要查询sport字段完全等于特定关键词的文档,直接修改getAnnotations方法,添加关键词参数并构建带条件的查询:
struct CustomFirestoreService { let store: Firestore = .firestore() init(){} // 新增关键词参数,实现精确查询 func getAnnotations(sportKeyword: String) async throws -> [Annotation]{ let ANNOTATIONS_PATH = "annotations" // 构建查询:筛选sport字段等于目标关键词的文档 let query = store.collection(ANNOTATIONS_PATH) .whereField("sport", isEqualTo: sportKeyword) let querySnapshot = try await query.getDocuments() return querySnapshot.documents.compactMap { document in do{ return try document.data(as: Annotation.self) }catch{ print(error) return nil } } } // 保留原方法用于获取全部文档 private func retrieve<FC : Codable>(path: String) async throws -> [FC]{ let querySnapshot = try await store.collection(path).getDocuments() return querySnapshot.documents.compactMap { document in do{ return try document.data(as: FC.self) }catch{ print(error) return nil } } } }
调用示例:
do { // 查询sport为"Football"的所有Annotation let footballAnnotations = try await CustomFirestoreService().getAnnotations(sportKeyword: "Football") // 处理查询结果 } catch { print("查询失败:\(error)") }
2. 包含子字符串的查询(进阶)
如果需要实现sport字段包含任意子字符串的查询(比如关键词"ball"匹配"Basketball"、"Football"),Firestore原生不支持直接的包含查询(无法高效利用索引),可以采用以下两种方案:
方案A:前缀匹配(仅匹配关键词开头的子字符串)
通过范围查询实现前缀匹配,适合关键词在字段开头的场景:
func getAnnotationsWithPrefix(sportPrefix: String) async throws -> [Annotation]{ let ANNOTATIONS_PATH = "annotations" // 利用Unicode最大值构建范围,匹配所有以sportPrefix开头的字符串 let query = store.collection(ANNOTATIONS_PATH) .whereField("sport", isGreaterThanOrEqualTo: sportPrefix) .whereField("sport", isLessThanOrEqualTo: sportPrefix + "\u{f8ff}") let querySnapshot = try await query.getDocuments() return querySnapshot.documents.compactMap { document in do{ return try document.data(as: Annotation.self) }catch{ print(error) return nil } } }
方案B:拆分关键词存储(支持任意子字符串匹配)
在Annotation结构体中新增sportKeywords数组字段,写入文档时将sport拆分为关键词(比如"Football"拆为["foot", "ball"]),然后用arrayContains查询:
首先修改Annotation结构体:
struct Annotation: Codable, Identifiable, Hashable { @DocumentID var id: String? let lat: String? let lng: String? var name: String var sport: String var headCoach: String // 新增字段:存储拆分后的关键词数组 var sportKeywords: [String] }
写入文档时维护sportKeywords字段(比如通过正则拆分单词,统一转为小写避免大小写问题),然后实现查询方法:
func getAnnotationsContainingKeyword(sportKeyword: String) async throws -> [Annotation]{ let ANNOTATIONS_PATH = "annotations" let query = store.collection(ANNOTATIONS_PATH) .whereField("sportKeywords", arrayContains: sportKeyword.lowercased()) let querySnapshot = try await query.getDocuments() return querySnapshot.documents.compactMap { document in do{ return try document.data(as: Annotation.self) }catch{ print(error) return nil } } }
内容的提问来源于stack exchange,提问作者Anish
相关产品推荐
相关产品推荐

