Iniziare a utilizzare le query pipeline
Sfondo
Le operazioni pipeline sono una nuova interfaccia di query per Firestore.
Questa interfaccia fornisce funzionalità di query avanzate che includono espressioni complesse. Inoltre, aggiunge il supporto per molte
nuove funzioni come min, max, substring, regex_match e array_contains_all.
Con le operazioni della pipeline, anche la creazione dell'indice è completamente facoltativa, il che semplifica
la procedura di sviluppo di nuove query. Le operazioni della pipeline rimuovono anche molte limitazioni sulla forma delle query, consentendoti di specificare query in o or di grandi dimensioni.
Per iniziare
Per installare e inizializzare gli SDK client, consulta le istruzioni riportate nelle guide seguenti:
- Inizia a utilizzare gli SDK web e per dispositivi mobili.
- Inizia a utilizzare le librerie client server.
Sintassi
Le sezioni seguenti forniscono una panoramica della sintassi per le operazioni della pipeline.
Concetti
Una differenza notevole rispetto alle operazioni della pipeline è l'introduzione dell'ordinamento esplicito delle "fasi". In questo modo è possibile esprimere query più complesse. Tuttavia, si tratta di una deviazione notevole dall'interfaccia di query esistente (operazioni principali), in cui l'ordinamento delle fasi era implicito. Considera il seguente esempio di operazione della pipeline:
Node.js
db.pipeline() .collection() // Step 1 (start a query with 'collection' scope) .where() // Step 2 (filter collection) .sort() // Step 3 (order results) .limit() // Step 4 (limit results) // Note: Applying a limit before a sort can yield unintended // results (as the limit would be applied before sorting).
Web
const pipeline = db.pipeline() // Step 1: Start a query with collection scope .collection("cities") // Step 2: Filter the collection .where(field("population").greaterThan(100000)) // Step 3: Sort the remaining documents .sort(field("name").ascending()) // Step 4: Return the top 10. Note applying the limit earlier in the // pipeline would have unintentional results. .limit(10);
Swift
let pipeline = db.pipeline() // Step 1: Start a query with collection scope .collection("cities") // Step 2: Filter the collection .where(Field("population").greaterThan(100000)) // Step 3: Sort the remaining documents .sort([Field("name").ascending()]) // Step 4: Return the top 10. Note applying the limit earlier in the pipeline would have // unintentional results. .limit(10)
Kotlin
Android
val pipeline = db.pipeline() // Step 1: Start a query with collection scope .collection("cities") // Step 2: Filter the collection .where(field("population").greaterThan(100000)) // Step 3: Sort the remaining documents .sort(field("name").ascending()) // Step 4: Return the top 10. Note applying the limit earlier in the pipeline would have // unintentional results. .limit(10)
Java
Android
Pipeline pipeline = db.pipeline() // Step 1: Start a query with collection scope .collection("cities") // Step 2: Filter the collection .where(field("population").greaterThan(100000)) // Step 3: Sort the remaining documents .sort(field("name").ascending()) // Step 4: Return the top 10. Note applying the limit earlier in the pipeline would have // unintentional results. .limit(10);
Python
from google.cloud.firestore_v1.pipeline_expressions import Field pipeline = ( client.pipeline() .collection("cities") .where(Field.of("population").greater_than(100_000)) .sort(Field.of("name").ascending()) .limit(10) )
Inizializzazione
Le operazioni della pipeline hanno una sintassi molto familiare derivata dalle query Firestore esistenti. Per iniziare, inizializza una query scrivendo quanto segue:
Node.js
const db = new Firestore({ projectId: '' , databaseId: databaseId'}) db.pipeline()
Java
Firestore db = FirestoreOptions.newBuilder().build().getService(); db.pipeline()
Struttura
Esistono alcuni termini importanti da comprendere quando crei operazioni della pipeline: fasi, espressioni e funzioni.

Fasi:una pipeline può essere costituita da una o più fasi. A livello logico, rappresentano la serie di passaggi (o fasi) eseguiti per eseguire la query. Nota: in pratica, le fasi potrebbero essere eseguite in ordine diverso per migliorare il rendimento. Tuttavia, ciò non modifica l'intento o la correttezza della query.
Espressioni:spesso gli stadi accettano un'espressione che ti consente di esprimere query più complesse. L'espressione può essere semplice e costituita da una singola funzione come eq("a", 1). Puoi anche esprimere espressioni più complesse nidificando espressioni come and(eq("a", 1), eq("b", 2)).
Riferimenti a campi e costanti
Le operazioni della pipeline supportano espressioni complesse. Pertanto, potrebbe essere necessario distinguere se un valore rappresenta un campo o una costante. Considera l'esempio seguente:
Node.js
// Here the two parameters "name" and "toronto" could represent fields or constants. db.pipeline() .collection("cities") .where(eq("name","toronto")) // In many cases, it's not necessary to differentiate between the two. In the // case of equality, we will implicit treat the first parameter as a field // reference and the second as a constant. However if you need to override you // can always be explicit with the value types db.pipeline() .collection("cities") .where(eq(Field.of("name"), Constant.of("toronto"))) // In some cases, being explicit is always required. However, it should be // enough to look at the type signature of the expressions to know what //parameters can be used with implicit types, and what should be explicitly specified.
Web
const pipeline = db.pipeline() .collection("cities") .where(field("name").equal(constant("Toronto")));
Swift
let pipeline = db.pipeline() .collection("cities") .where(Field("name").equal(Constant("Toronto")))
Kotlin
Android
val pipeline = db.pipeline() .collection("cities") .where(field("name").equal(constant("Toronto")))
Java
Android
Pipeline pipeline = db.pipeline() .collection("cities") .where(field("name").equal(constant("Toronto")));
Python
from google.cloud.firestore_v1.pipeline_expressions import Field, Constant pipeline = ( client.pipeline() .collection("cities") .where(Field.of("name").equal(Constant.of("Toronto"))) )
Fasi
Fasi di input
La fase di input rappresenta la prima fase di una query. Definisce l'insieme iniziale di documenti su cui esegui la query. Per le operazioni della pipeline, questo è in gran parte simile alle query esistenti, in cui la maggior parte delle query inizia con una fase collection(...) o collection_group(...). Sono state aggiunte due nuove fasi di input: database() e documents(...). database() consente di restituire tutti i documenti nel database, mentre documents(...) funziona in modo identico a una lettura batch.
Node.js
// Return all restaurants in San Francisco const results = await db.pipeline() .collection("cities/sf/restaurants") .execute(); // Return all restaurants const results = await db.pipeline() .collectionGroup("restaurants") .execute(); // Return all documents across all collections in the database (huge result!) const results = await db.pipeline() .database() .execute(); // Batch read of 3 documents const results = await db.pipeline() .documents( db.collection("cities").doc("SF"), db.collection("cities").doc("DC"), db.collection("cities").doc("NY")) .execute();
Web
let results; // Return all restaurants in San Francisco results = await execute(db.pipeline().collection("cities/sf/restaurants")); // Return all restaurants results = await execute(db.pipeline().collectionGroup("restaurants")); // Return all documents across all collections in the database (the entire database) results = await execute(db.pipeline().database()); // Batch read of 3 documents results = await execute(db.pipeline().documents([ doc(db, "cities", "SF"), doc(db, "cities", "DC"), doc(db, "cities", "NY") ]));
Swift
var results: Pipeline.Snapshot // Return all restaurants in San Francisco results = try await db.pipeline().collection("cities/sf/restaurants").execute() // Return all restaurants results = try await db.pipeline().collectionGroup("restaurants").execute() // Return all documents across all collections in the database (the entire database) results = try await db.pipeline().database().execute() // Batch read of 3 documents results = try await db.pipeline().documents([ db.collection("cities").document("SF"), db.collection("cities").document("DC"), db.collection("cities").document("NY") ]).execute()
Kotlin
Android
var results: Task<Pipeline.Snapshot> // Return all restaurants in San Francisco results = db.pipeline().collection("cities/sf/restaurants").execute() // Return all restaurants results = db.pipeline().collectionGroup("restaurants").execute() // Return all documents across all collections in the database (the entire database) results = db.pipeline().database().execute() // Batch read of 3 documents results = db.pipeline().documents( db.collection("cities").document("SF"), db.collection("cities").document("DC"), db.collection("cities").document("NY") ).execute()
Java
Android
Task<Pipeline.Snapshot> results; // Return all restaurants in San Francisco results = db.pipeline().collection("cities/sf/restaurants").execute(); // Return all restaurants results = db.pipeline().collectionGroup("restaurants").execute(); // Return all documents across all collections in the database (the entire database) results = db.pipeline().database().execute(); // Batch read of 3 documents results = db.pipeline().documents( db.collection("cities").document("SF"), db.collection("cities").document("DC"), db.collection("cities").document("NY") ).execute();
Python
# Return all restaurants in San Francisco results = client.pipeline().collection("cities/sf/restaurants").execute() # Return all restaurants results = client.pipeline().collection_group("restaurants").execute() # Return all documents across all collections in the database (the entire database) results = client.pipeline().database().execute() # Batch read of 3 documents results = ( client.pipeline() .documents( client.collection("cities").document("SF"), client.collection("cities").document("DC"), client.collection("cities").document("NY"), ) .execute() )
Come per tutte le altre fasi, l'ordine dei risultati di queste fasi di input non è
stabile. Un operatore sort(...) deve sempre essere aggiunto se si desidera un ordinamento specifico.
Dove
La fase where(...) funge da operazione di filtro tradizionale sui documenti
generati dalla fase precedente e rispecchia per lo più la sintassi "where"
per le query esistenti. Qualsiasi documento per cui una determinata espressione restituisce un valore
diverso da true viene filtrato dai documenti restituiti.
È possibile concatenare più istruzioni where(...), che fungono da espressione and(...). Ad esempio, le due query seguenti sono logicamente equivalenti e possono essere utilizzate in modo intercambiabile.
Node.js
const results = await db.pipeline() .collection("books") .where(eq("rating", 5.0)) .where(lt('published', 1900)) .execute(); const results = await db.pipeline() .collection("books") .where(and( eq("rating", 5.0), lt('published', 1900))) .execute();
Web
let results; results = await execute(db.pipeline().collection("books") .where(field("rating").equal(5)) .where(field("published").lessThan(1900)) ); results = await execute(db.pipeline().collection("books") .where(and(field("rating").equal(5), field("published").lessThan(1900))) );
Swift
var results: Pipeline.Snapshot results = try await db.pipeline().collection("books") .where(Field("rating").equal(5)) .where(Field("published").lessThan(1900)) .execute() results = try await db.pipeline().collection("books") .where(Field("rating").equal(5) && Field("published").lessThan(1900)) .execute()
Kotlin
Android
var results: Task<Pipeline.Snapshot> results = db.pipeline().collection("books") .where(field("rating").equal(5)) .where(field("published").lessThan(1900)) .execute() results = db.pipeline().collection("books") .where(Expression.and(field("rating").equal(5), field("published").lessThan(1900))) .execute()
Java
Android
Task<Pipeline.Snapshot> results; results = db.pipeline().collection("books") .where(field("rating").equal(5)) .where(field("published").lessThan(1900)) .execute(); results = db.pipeline().collection("books") .where(Expression.and( field("rating").equal(5), field("published").lessThan(1900) )) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import And, Field results = ( client.pipeline() .collection("books") .where(Field.of("rating").equal(5)) .where(Field.of("published").less_than(1900)) .execute() ) results = ( client.pipeline() .collection("books") .where(And(Field.of("rating").equal(5), Field.of("published").less_than(1900))) .execute() )
Selezionare / aggiungere e rimuovere campi
select(...), add_fields(...) e remove_fields(...) ti consentono di modificare i campi restituiti da una fase precedente. Questi tre tipi sono
generalmente indicati come palcoscenici in stile proiezione.
select(...) e add_fields(...) ti consentono di specificare il risultato di un'espressione in un nome di campo fornito dall'utente. Un'espressione che genera un errore
restituirà un valore null. select(...) restituirà solo i documenti con i nomi dei campi specificati, mentre add_fields(...) estende lo schema della fase precedente (sovrascrivendo potenzialmente i valori con nomi dei campi identici).
remove_fields(...) consente di specificare un insieme di campi da rimuovere dalla
fase precedente. La specifica di nomi di campi inesistenti è un'operazione no-op.
Consulta la sezione Limita i campi da restituire di seguito, ma in generale l'utilizzo di una fase di questo tipo per limitare il risultato ai soli campi necessari nel client è utile per ridurre i costi e la latenza per la maggior parte delle query.
Aggregazione / Valori univoci
La fase aggregate(...) ti consente di eseguire una serie di aggregazioni sui documenti di input. Per impostazione predefinita, tutti i documenti vengono aggregati, ma è possibile fornire un argomento grouping facoltativo, che consente di aggregare i documenti di input in bucket diversi.
Node.js
const results = await db.pipeline() .collection("books") .aggregate({ accumulators: [avg('rating').as('avg_rating')], groups: ['genre'], }) .execute();
Web
const results = await execute(db.pipeline() .collection("books") .aggregate( field("rating").average().as("avg_rating") ) .distinct(field("genre")) );
Swift
let results = try await db.pipeline() .collection("books") .aggregate([ Field("rating").average().as("avg_rating") ], groups: [ Field("genre") ]) .execute()
Kotlin
Android
val results = db.pipeline() .collection("books") .aggregate( AggregateStage .withAccumulators(AggregateFunction.average("rating").alias("avg_rating")) .withGroups(field("genre")) ) .execute()
Java
Android
Task<Pipeline.Snapshot> results = db.pipeline() .collection("books") .aggregate(AggregateStage .withAccumulators( AggregateFunction.average("rating").alias("avg_rating")) .withGroups(field("genre"))) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field results = ( client.pipeline() .collection("books") .aggregate( Field.of("rating").average().as_("avg_rating"), groups=[Field.of("genre")] ) .execute() )
Se groupings non è specificato, questa fase produrrà un solo documento. In caso contrario, verrà generato un documento per ogni combinazione univoca di valori di groupings.
La fase distinct(...) è un operatore di aggregazione semplificato che consente di generare solo il groupings univoco senza accumulatori. Per tutti gli altri aspetti, si comporta in modo identico a aggregate(...). Di seguito è riportato un esempio:
Node.js
const results = await db.pipeline() .collection("books") .distinct(toUppercase(Field.of("author")).as("author"), Field.of("genre")) .execute();
Web
const results = await execute(db.pipeline() .collection("books") .distinct( field("author").toUpper().as("author"), field("genre") ) );
Swift
let results = try await db.pipeline() .collection("books") .distinct([ Field("author").toUpper().as("author"), Field("genre") ]) .execute()
Kotlin
Android
val results = db.pipeline() .collection("books") .distinct( field("author").toUpper().alias("author"), field("genre") ) .execute()
Java
Android
Task<Pipeline.Snapshot> results = db.pipeline() .collection("books") .distinct( field("author").toUpper().alias("author"), field("genre") ) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field results = ( client.pipeline() .collection("books") .distinct(Field.of("author").to_upper().as_("author"), "genre") .execute() )
Funzioni
Le funzioni sono un blocco predefinito per la creazione di espressioni e query complesse. Per un elenco completo di funzioni con esempi, consulta il riferimento alle funzioni. Come promemoria, considera la struttura di una query tipica:

Molte fasi accettano espressioni che contengono una o più funzioni. L'utilizzo più comune delle funzioni si trova nelle fasi where(...) e select(...). Esistono due tipi principali di funzioni con cui devi avere familiarità:
Node.js
// Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. const results = await db.pipeline() .collection("books") .select(logicalMin(Field.of("current"),Field.of("updated")).as("price_min")) .execute(); // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. const results = await db.pipeline() .collection("books") .aggregate(min(Field.of("price")) .execute();
Web
let results; // Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results = await execute(db.pipeline().collection("books") .select(field("current").logicalMinimum(field("updated")).as("price_min")) ); // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results = await execute(db.pipeline().collection("books") .aggregate(field("price").minimum().as("min_price")) );
Swift
var results: Pipeline.Snapshot // Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results = try await db.pipeline().collection("books") .select([ Field("current").logicalMinimum(["updated"]).as("price_min") ]) .execute() // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results = try await db.pipeline().collection("books") .aggregate([Field("price").minimum().as("min_price")]) .execute()
Kotlin
Android
var results: Task<Pipeline.Snapshot> // Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results = db.pipeline().collection("books") .select( field("current").logicalMinimum("updated").alias("price_min") ) .execute() // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results = db.pipeline().collection("books") .aggregate(AggregateFunction.minimum("price").alias("min_price")) .execute()
Java
Android
Task<Pipeline.Snapshot> results; // Type 1: Scalar (for use in non-aggregation stages) // Example: Return the min store price for each book. results = db.pipeline().collection("books") .select( field("current").logicalMinimum("updated").alias("price_min") ) .execute(); // Type 2: Aggregation (for use in aggregate stages) // Example: Return the min price of all books. results = db.pipeline().collection("books") .aggregate(AggregateFunction.minimum("price").alias("min_price")) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field # Type 1: Scalar (for use in non-aggregation stages) # Example: Return the min store price for each book. results = ( client.pipeline() .collection("books") .select( Field.of("current").logical_minimum(Field.of("updated")).as_("price_min") ) .execute() ) # Type 2: Aggregation (for use in aggregate stages) # Example: Return the min price of all books. results = ( client.pipeline() .collection("books") .aggregate(Field.of("price").minimum().as_("min_price")) .execute() )
Limiti
Nella maggior parte dei casi, Enterprise Edition non impone limiti alla forma della query. In altre parole, non sei limitato a un numero ridotto di valori in una query IN
o OR. Esistono invece due limiti principali di cui devi essere a conoscenza:
- Scadenza: 60 secondi (identica a Standard Edition).
- Utilizzo della memoria:limite di 128 MiB per la quantità di dati materializzati durante l'esecuzione della query.
Errori
Potresti riscontrare query non riuscite per diversi motivi. Ecco un link agli errori comuni e all'azione associata che puoi intraprendere:
| Codice di errore | Azione |
DEADLINE_EXCEEDED
|
La query che stai eseguendo supera il limite di 60 secondi e richiede un'ulteriore ottimizzazione. Per suggerimenti, consulta la sezione Rendimento. Se non riesci a individuare la causa principale del problema, contatta il team. |
RESOURCE_EXHAUSTED
|
La query che stai eseguendo supera i limiti di memoria e richiede un'ulteriore ottimizzazione. Per suggerimenti, consulta la sezione Rendimento. Se non riesci a individuare la causa principale del problema, contatta il team. |
INTERNAL
|
Contatta il team per ricevere assistenza. |
Rendimento
A differenza delle query esistenti, le operazioni della pipeline non richiedono la presenza di un indice. Ciò significa che una query può mostrare una latenza maggiore rispetto alle query esistenti, che avrebbero semplicemente restituito immediatamente un errore di indice mancante FAILED_PRECONDITION. Per migliorare le prestazioni delle operazioni della pipeline, puoi eseguire alcuni passaggi.
Crea indici
Indice utilizzato
Query Explain ti consente di identificare se la query viene pubblicata da un indice o se viene eseguita un'operazione meno efficiente, come una scansione della tabella. Se la query non viene pubblicata completamente da un indice, puoi crearne uno seguendo le istruzioni.
Creazione di indici
Per creare gli indici, puoi seguire la documentazione esistente sulla gestione degli indici. Prima di creare un indice, acquisisci familiarità con le best practice generali per gli indici in Firestore. Per assicurarti che la query possa sfruttare gli indici, segui le best practice per creare indici con campi nel seguente ordine:
- Tutti i campi che verranno utilizzati nei filtri di uguaglianza (in qualsiasi ordine)
- Tutti i campi in base ai quali verrà eseguito l'ordinamento (nello stesso ordine)
- Campi che verranno utilizzati nei filtri di intervallo o di disuguaglianza in ordine decrescente di selettività del vincolo di query
Ad esempio, per la seguente query:
Node.js
const results = await db.pipeline() .collection('books') .where(lt('published', 1900)) .where(eq('genre', 'Science Fiction')) .where(gt('avg_rating', 4.3)) .sort(Field.of('published').descending()) .execute();
Web
const results = await execute(db.pipeline() .collection("books") .where(field("published").lessThan(1900)) .where(field("genre").equal("Science Fiction")) .where(field("rating").greaterThan(4.3)) .sort(field("published").descending()) );
Swift
let results = try await db.pipeline() .collection("books") .where(Field("published").lessThan(1900)) .where(Field("genre").equal("Science Fiction")) .where(Field("rating").greaterThan(4.3)) .sort([Field("published").descending()]) .execute()
Kotlin
Android
val results = db.pipeline() .collection("books") .where(field("published").lessThan(1900)) .where(field("genre").equal("Science Fiction")) .where(field("rating").greaterThan(4.3)) .sort(field("published").descending()) .execute()
Java
Android
Task<Pipeline.Snapshot> results = db.pipeline() .collection("books") .where(field("published").lessThan(1900)) .where(field("genre").equal("Science Fiction")) .where(field("rating").greaterThan(4.3)) .sort(field("published").descending()) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field results = ( client.pipeline() .collection("books") .where(Field.of("published").less_than(1900)) .where(Field.of("genre").equal("Science Fiction")) .where(Field.of("rating").greater_than(4.3)) .sort(Field.of("published").descending()) .execute() )
L'indice consigliato è un indice dell'ambito della raccolta su books per (genre [...], published DESC, avg_rating DESC).
Densità dell'indice
Firestore supporta indici sparsi e non sparsi. Per ulteriori informazioni, vedi Densità dell'indice.
Query coperte + indici secondari
Firestore può saltare il recupero dell'intero documento e restituire solo i risultati dell'indice se tutti i campi restituiti sono presenti in un indice secondario. Ciò in genere comporta un miglioramento significativo della latenza (e dei costi). Utilizzando la query di esempio riportata di seguito:
Node.js
const results = await db.pipeline() .collection("books") .where(like(Field.of("category"), "%fantasy%")) .where(exists("title")) .where(exists("author")) .select("title", "author") .execute();
Web
const results = await execute(db.pipeline() .collection("books") .where(field("category").like("%fantasy%")) .where(field("title").exists()) .where(field("author").exists()) .select(field("title"), field("author")) );
Swift
let results = try await db.pipeline() .collection("books") .where(Field("category").like("%fantasy%")) .where(Field("title").exists()) .where(Field("author").exists()) .select([Field("title"), Field("author")]) .execute()
Kotlin
Android
val results = db.pipeline() .collection("books") .where(field("category").like("%fantasy%")) .where(field("title").exists()) .where(field("author").exists()) .select(field("title"), field("author")) .execute()
Java
Android
Task<Pipeline.Snapshot> results = db.pipeline() .collection("books") .where(field("category").like("%fantasy%")) .where(field("title").exists()) .where(field("author").exists()) .select(field("title"), field("author")) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field results = ( client.pipeline() .collection("books") .where(Field.of("category").like("%fantasy%")) .where(Field.of("title").exists()) .where(Field.of("author").exists()) .select("title", "author") .execute() )
Se il database ha già un indice dell'ambito della raccolta su books per (category [...], title [...], author [...]), può evitare di recuperare qualsiasi elemento dai documenti principali. In questo caso, l'ordine nell'indice non ha importanza, [...] viene utilizzato per indicarlo.
Limitare i campi da restituire
Per impostazione predefinita, una query Firestore restituisce tutti i campi di un documento, in modo analogo a un SELECT * nei sistemi tradizionali. Se invece la tua applicazione ha bisogno solo di un sottoinsieme dei campi, le fasi select(...) o restrict(...) possono essere utilizzate per eseguire questo filtraggio lato server. In questo modo si riducono sia le dimensioni della risposta (diminuendo il costo del traffico in uscita della rete) sia la latenza.
Strumenti per la risoluzione dei problemi
Query Explain
Query Explain ti consente di visualizzare le metriche di esecuzione e i dettagli sugli indici utilizzati.
Metriche
Operazioni della pipeline se completamente integrate con le metriche Firestore esistenti.
Problemi noti / limitazioni
Indici specializzati
Le operazioni della pipeline non supportano ancora i tipi di indice array-contains e vector esistenti. Anziché rifiutare semplicemente queste query, Firestore tenterà di utilizzare altri indici ascending e descending esistenti. Si prevede che durante l'anteprima privata le operazioni della pipeline con queste espressioni array_contains o find_nearest saranno più lente rispetto alle loro equivalenti esistenti.
Impaginazione
Il supporto per la paginazione semplice di un insieme di risultati non è supportato durante l'anteprima privata. Questo problema può essere risolto concatenando le fasi where(...) e sort(...) equivalenti, come mostrato di seguito.
Node.js
// Existing pagination via 'startAt(...)'. db.collection("cities") .orderBy("population") .startAt(1000000); // Near-term work around via Pipeline operations. db.pipeline() .collection("cities") .where(gte("population", 1000000) .sort(Field.of("population").descending());
Web
// Existing pagination via `startAt()` const q = query(collection(db, "cities"), orderBy("population"), startAt(1000000)); // Private preview workaround using pipelines const pageSize = 2; const pipeline = db.pipeline() .collection("cities") .select("name", "population", "__name__") .sort(field("population").descending(), field("__name__").ascending()); // Page 1 results let snapshot = await execute(pipeline.limit(pageSize)); // End of page marker const lastDoc = snapshot.results[snapshot.results.length - 1]; // Page 2 results snapshot = await execute( pipeline .where( or( and( field("population").equal(lastDoc.get("population")), field("__name__").greaterThan(lastDoc.ref) ), field("population").lessThan(lastDoc.get("population")) ) ) .limit(pageSize) );
Swift
// Existing pagination via `start(at:)` let query = db.collection("cities").order(by: "population").start(at: [1000000]) // Private preview workaround using pipelines let pipeline = db.pipeline() .collection("cities") .where(Field("population").greaterThanOrEqual(1000000)) .sort([Field("population").descending()])
Kotlin
Android
// Existing pagination via `startAt()` val query = db.collection("cities").orderBy("population").startAt(1000000) // Private preview workaround using pipelines val pipeline = db.pipeline() .collection("cities") .where(field("population").greaterThanOrEqual(1000000)) .sort(field("population").descending())
Java
Android
// Existing pagination via `startAt()` Query query = db.collection("cities").orderBy("population").startAt(1000000); // Private preview workaround using pipelines Pipeline pipeline = db.pipeline() .collection("cities") .where(field("population").greaterThanOrEqual(1000000)) .sort(field("population").descending());
Python
from google.cloud.firestore_v1.pipeline_expressions import Field # Existing pagination via `start_at()` query = ( client.collection("cities") .order_by("population") .start_at({"population": 1_000_000}) ) # Private preview workaround using pipelines pipeline = ( client.pipeline() .collection("cities") .where(Field.of("population").greater_than_or_equal(1_000_000)) .sort(Field.of("population").descending()) )
Assistenza per l'emulatore
L'emulatore non supporta ancora le operazioni della pipeline.
Supporto in tempo reale e offline
Le operazioni della pipeline non dispongono ancora di funzionalità in tempo reale e offline.
Passaggi successivi
- Consulta il riferimento alle funzioni.