Si tengo una colección simple como:
Fruits: Banana: title: "Banana" vitamins: ["potassium","B6","C"] Apple: title: "Apple" vitamins: ["A","B6","C"]Y si quiero buscar frutas que contengan vitamina B6, haría lo siguiente:
db.collection("Fruits").whereField("vitamins", arrayContains: "A").getDocuments() { (querySnapshot, err) in if let err = err { print("Error getting documents: \(err)") } else { for document in querySnapshot!.documents { print("\(document.documentID) => \(document.data())") } } } Y eso me mostraría todas las frutas en mi colección que contienen vitamina A. Sin embargo, ¿cómo podría buscar frutas que contienen múltiples vitaminas, digamos vitaminas B6 y C? No puedo simplemente buscar ["B6","C"] ya que entonces estaría buscando una matriz en lugar de cadenas independientes.
¿Es esto posible en Cloud Firestore? Si no, ¿hay alguna forma alternativa de hacer esto?
Sería tentador buscar documentos que coincidan con múltiples condiciones, encadenando las condiciones en la consulta:
db.collection("Fruits") .whereField("vitamins", arrayContains: "B6") .whereField("vitamins", arrayContains: "C")Pero la documentación sobre consultas compuestas sugiere que actualmente no puede tener varias condiciones arrayContains en una sola consulta.
Entonces, no es posible con lo que tienes hoy. Considere en cambio usar una estructura de mapa en lugar de una matriz:
Fruits: Banana: title: "Banana" vitamins: { "potassium": true, "B6": true, "C": true }Entonces podrías consultar así:
db.collection("Fruits") .whereField("vitamins.B6", isEqualTo: true) .whereField("vitamins.C", isEqualTo: true)Firestore introdujo los métodos whereIn, arrayContains y arrayContainsAny a finales de 2019. Estos métodos realizan consultas lógicas "OR", pero tienen un límite de 10 cláusulas que puede pasar (por lo que puede buscar un máximo de 10 vitaminas).
Algunas soluciones ya mencionadas reestructuran sus datos. Otra solución que aprovecha el enfoque de reestructuración es no incluir las vitaminas en el documento Fruit, sino al revés. De esta forma, obtendrá todos los documentos de los que forma parte 'Banana'.
let vitaminsRef = db.collection('Vitamins').where('fruits', arrayContains: 'banana');Esta solución le permite eludir el límite de 10 cláusulas. Obtiene todos los documentos de 'Vitamina' que tienen 'Banana' en su matriz de 'Frutas' en una sola operación de lectura (piense en la paginación, si son demasiados).
No hay forma de realizar múltiples consultas de contenido de matriz en Firestore. Sin embargo, puede combinar tantas condiciones como sea posible where la práctica. Por lo tanto, considere esto:
[Fruits] <Banana> title: "Banana" vitamins: potassium: true b6: true c: true Firestore.firestore().collection("Fruits").whereField("vitamins.potassium", isEqualTo: true).whereField("vitamins.b6", isEqualTo: true) Sin embargo, esto todavía no permite una búsqueda OR limpia. Para consultar frutas con vitamina x o vitamina y, debe ser más creativo. Además, este enfoque no debe usarse si hay muchos valores posibles y deben combinarse con consultas compuestas. Esto se debe a que Firestore no permite más de 200 índices compuestos y cada índice compuesto necesitaría especificar la vitamina exacta. Lo que significa que tendría que crear un índice compuesto individual para vitamins.b6 , vitamins.potassium , etc. y solo tiene 200 en total.