Consultas con filtros de intervalo y de desigualdad en varios campos
Firestore admite el uso de filtros de intervalo y de desigualdad en varios campos en una sola consulta. Puedes incluir condiciones de intervalo y de desigualdad en varios campos y simplificar el desarrollo de tu aplicación delegando la implementación de la lógica de postfiltrado en Firestore.
Filtros de intervalo y desigualdad en varios campos
La siguiente consulta usa filtros de intervalo en la población y la densidad para devolver todas las ciudades en las que la población es superior a 1.000.000 de personas y la densidad de población es inferior a 10.000 personas por unidad de superficie.
Versión web 9 modular
const q = query(
collection(db, "cities"),
where('population', '>', 1000000),
where('density', '<', 10000),
);
Swift
let query = db.collection("cities")
.whereField("population", isGreaterThan: 1000000)
.whereField("density", isLessThan: 10000)
Objective‑C
FIRQuery *query =
[[[[self.db collectionWithPath:@"cities"]
queryWhereField:@"population" isGreaterThan:@1000000]
queryWhereField:@"density" isLessThan:@10000];
Java Android
Query query = db.collection("cities")
.whereGreaterThan("population", 1000000)
.whereLessThan("density", 10000);
Android con Kotlin y KTX
val query = db.collection("cities")
.whereGreaterThan("population", 1000000)
.whereLessThan("density", 10000)
Go
query := client.Collection("cities").
Where("population", ">", 1000000).
Where("density", "<", 10000)
Java
db.collection("cities")
.whereGreaterThan("population", 1000000)
.whereLessThan("density", 10000);
Node.js
db.collection("cities")
.where('population', '>', 1000000),
.where('density', '<', 10000)
Python
from google.cloud import firestore
db = firestore.Client()
query = db.collection("cities")
.where("population", ">", 1000000)
.where("density", "<", 10000)
PHP
C#
Ruby
query = cities_ref.where("population", ">", "1000000")
.where("density", "<", 10000)
C++
CollectionReference cities_ref = db->Collection("cities");
Query query = cities_ref.WhereGreaterThan("population", FieldValue::Integer(1000000))
.WhereLessThan("density", FieldValue::Integer(10000));
Unity
CollectionReference citiesRef = db.Collection("cities");
Query query = citiesRef.WhereGreaterThan("population", 1000000)
.WhereLessThan("density", 10000);
Dart
final citiesRef = FirebaseFirestore.instance.collection('cities')
final query = citiesRef.where("population", isGreaterThan: 1000000)
.where("density", isLessThan: 10000);
Consideraciones sobre la indexación
Antes de ejecutar las consultas, consulta información sobre las consultas y el modelo de datos de Firestore.
En Firestore, la cláusula ORDER BY
de una consulta determina qué índices se pueden usar para servir la consulta. Por ejemplo, una consulta ORDER BY a ASC, b ASC
requiere un índice compuesto en los campos a ASC, b ASC
.
Para optimizar el rendimiento y el coste de las consultas de Firestore, optimiza el orden de los campos del índice. Para ello, asegúrate de que el índice esté ordenado de izquierda a derecha de forma que la consulta se limite a un conjunto de datos que impida analizar entradas de índice innecesarias.
Supongamos que quieres buscar en una colección de empleados y encontrar a los empleados de Estados Unidos cuyo salario sea superior a 100.000 $y cuyo número de años de experiencia sea superior a 0. Según tu conocimiento del conjunto de datos, sabes que la restricción de salario es más selectiva que la de experiencia. El índice ideal que reduciría el número de análisis de índices sería (salary [...], experience [...])
. Por lo tanto, la consulta que sería rápida y eficiente en cuanto a costes ordenaría salary
antes que experience
y tendría el siguiente aspecto:
Java
db.collection("employees")
.whereGreaterThan("salary", 100000)
.whereGreaterThan("experience", 0)
.orderBy("salary")
.orderBy("experience");
Node.js
db.collection("employees")
.where("salary", ">", 100000)
.where("experience", ">", 0)
.orderBy("salary")
.orderBy("experience");
Python
db.collection("employees")
.where("salary", ">", 100000)
.where("experience", ">", 0)
.order_by("salary")
.order_by("experience");
Prácticas recomendadas para optimizar los índices
Cuando optimices los índices, ten en cuenta las siguientes prácticas recomendadas.
Ordenar los campos de índice por igualdades seguidas del campo de intervalo o desigualdad más selectivo
Firestore usa los campos situados más a la izquierda de un índice compuesto para satisfacer las restricciones de igualdad y la restricción de intervalo o desigualdad, si la hay, en el primer campo de la consulta orderBy()
. Estas restricciones pueden reducir el número de entradas de índice que analiza Firestore. Firestore usa los campos restantes del índice para cumplir otras restricciones de intervalo o desigualdad de la consulta. Estas restricciones no reducen el número de entradas de índice que analiza Firestore, sino que filtran los documentos que no coinciden para que se reduzca el número de documentos que se devuelven a los clientes.
Para obtener más información sobre cómo crear índices eficientes, consulta las propiedades de los índices.
Ordenar los campos en orden descendente de selectividad de la restricción de consulta
Para asegurarte de que Firestore selecciona el índice óptimo para tu consulta, especifica una cláusula orderBy()
que ordene los campos en orden decreciente de selectividad de las restricciones de la consulta. Una selectividad más alta se corresponde con un subconjunto de documentos más pequeño, mientras que una selectividad más baja se corresponde con un subconjunto de documentos más grande. Asegúrate de seleccionar los campos de intervalo o desigualdad con mayor selectividad antes en el orden del índice que los campos con menor selectividad.
Para minimizar el número de documentos que Firestore analiza y devuelve a través de la red, siempre debe ordenar los campos en orden decreciente de selectividad de las restricciones de consulta. Si el conjunto de resultados no está en el orden requerido y se espera que sea pequeño, puede implementar una lógica del lado del cliente para reordenarlo según sus expectativas.
Por ejemplo, supongamos que quieres buscar en una colección de empleados a los que residen en Estados Unidos y cuyo salario es superior a 100.000 USD,y ordenar los resultados por el año de experiencia del empleado. Si crees que solo un pequeño número de empleados tendrá un salario superior a 100.000 USD, la forma más eficiente de escribir la consulta es la siguiente:
Java
db.collection("employees")
.whereGreaterThan("salary", 100000)
.orderBy("salary")
.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
// Order results by `experience`
}
});;
Node.js
const querySnapshot = await db.collection('employees')
.where("salary", ">", 100000)
.orderBy("salary")
.get();
// Order results by `experience`
Python
results = db.collection("employees")
.where("salary", ">", 100000)
.order_by("salary")
.stream()
// Order results by `experience`
Aunque añadir un orden a experience
en la consulta dará como resultado el mismo conjunto de documentos y evitará que se vuelvan a ordenar los resultados en los clientes, la consulta puede leer muchas más entradas de índice extrañas que la consulta anterior. Esto se debe a que Firestore siempre prefiere un índice cuyo prefijo de campos de índice coincida con la cláusula "order by" de la consulta. Si se añade experience
a la cláusula "order by", Firestore seleccionará el índice (experience [...], salary [...])
para calcular los resultados de la consulta. Como no hay otras restricciones en experience
, Firestore leerá todas las entradas de índice de la colección employees
antes de aplicar el filtro salary
para encontrar el conjunto de resultados final. Esto significa que las entradas de índice que no cumplen el filtro salary
se siguen leyendo, lo que aumenta la latencia y el coste de la consulta.
Precios
Las consultas con filtros de intervalo y de desigualdad en varios campos se facturan en función de los documentos leídos y las entradas de índice leídas.
Para obtener información detallada, consulta la página Precios.
Limitaciones
Además de las limitaciones de las consultas, ten en cuenta las siguientes limitaciones antes de usar consultas con filtros de intervalo y de desigualdad en varios campos:
- No se admiten las consultas con filtros de intervalo o de desigualdad en los campos de documentos y solo con restricciones de igualdad en la clave de documento
(__name__)
. - Firestore limita el número de campos de intervalo o desigualdad a 10. De esta forma, se evita que las consultas resulten demasiado caras.
Siguientes pasos
- Consulta cómo optimizar tus consultas.
- Más información sobre cómo hacer consultas simples y compuestas
- Consulta cómo usa Firestore los índices.