Firestore Pipelines ऑपरेशन का इस्तेमाल शुरू करना

बैकग्राउंड

पाइपलाइन क्वेरी, Firestore के लिए एक नया क्वेरी इंटरफ़ेस है. इसमें ऐडवांस क्वेरी की सुविधा मिलती है. इसमें मुश्किल एक्सप्रेशन भी शामिल हैं. इसमें कई नए फ़ंक्शन भी जोड़े गए हैं. जैसे, min, max, substring, regex_match और array_contains_all. पाइपलाइन क्वेरी की मदद से, इंडेक्स बनाने का विकल्प भी पूरी तरह से उपलब्ध होता है. इससे नई क्वेरी डेवलप करने की प्रोसेस आसान हो जाती है. पाइपलाइन क्वेरी की मदद से, क्वेरी के स्ट्रक्चर से जुड़ी कई पाबंदियां भी हट जाती हैं. इससे आपको बड़ी in या or क्वेरी तय करने की सुविधा मिलती है.

शुरू करें

क्लाइंट एसडीके इंस्टॉल करने और शुरू करने के लिए, शुरुआती निर्देश में दिए गए निर्देशों को पढ़ें.

सिंटैक्स

यहां दिए गए सेक्शन में, पाइपलाइन क्वेरी के सिंटैक्स के बारे में खास जानकारी दी गई है.

कॉन्सेप्ट

पाइपलाइन क्वेरी से एक अहम अंतर यह है कि इसमें "स्टेज" के क्रम को साफ़ तौर पर बताया गया है. इससे ज़्यादा मुश्किल क्वेरी को भी आसानी से पूछा जा सकता है. हालांकि, यह मौजूदा क्वेरी इंटरफ़ेस से काफ़ी अलग है. इसमें चरणों के क्रम के बारे में बताया गया था. पाइपलाइन क्वेरी का यह उदाहरण देखें:

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

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

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)
)

डेटा लेयर में इवेंट बनाने की प्रोसेस

पाइपलाइन क्वेरी का सिंटैक्स, मौजूदा Cloud Firestore क्वेरी के सिंटैक्स से मिलता-जुलता है. शुरू करने के लिए, यहां दिया गया कोड लिखें:

Web

const { getFirestore } = require("firebase/firestore");
const { execute } = require("firebase/firestore/pipelines");
const database = getFirestore(app, "enterprise");
const pipeline = database.pipeline();
Swift
let firestore = Firestore.firestore(database: "enterprise")
let pipeline = firestore.pipeline()

Kotlin

val firestore = Firebase.firestore("enterprise")
val pipeline = firestore.pipeline()

Java

FirebaseFirestore firestore = FirebaseFirestore.getInstance("enterprise");
PipelineSource pipeline = firestore.pipeline();
Python
firestore_client = firestore.client(default_app, "your-new-enterprise-database")
pipeline = firestore_client.pipeline()

बनावट

पाइपलाइन क्वेरी बनाते समय, कुछ शब्दों को समझना ज़रूरी है: स्टेज, एक्सप्रेशन, और फ़ंक्शन.

क्वेरी में चरणों और एक्सप्रेशन को दिखाने वाला उदाहरण

स्टेज: पाइपलाइन में एक या उससे ज़्यादा स्टेज हो सकते हैं. तर्क के हिसाब से, ये क्वेरी को लागू करने के लिए उठाए गए चरणों (या चरणों) की सीरीज़ को दिखाते हैं. ध्यान दें: परफ़ॉर्मेंस को बेहतर बनाने के लिए, चरणों को क्रम से लागू नहीं किया जा सकता. हालांकि, इससे क्वेरी के मकसद या सही होने में कोई बदलाव नहीं होता है.

एक्सप्रेशन: स्टेज अक्सर एक एक्सप्रेशन स्वीकार करते हैं. इससे आपको ज़्यादा जटिल क्वेरी को एक्सप्रेस करने की अनुमति मिलती है. एक्सप्रेशन आसान हो सकता है और इसमें eq("a", 1) जैसे एक फ़ंक्शन शामिल हो सकता है. and(eq("a", 1), eq("b", 2)). जैसे एक्सप्रेशन को नेस्ट करके, ज़्यादा कॉम्प्लेक्स एक्सप्रेशन भी बनाए जा सकते हैं

फ़ील्ड बनाम कॉन्स्टेंट रेफ़रंस

पाइपलाइन क्वेरी में मुश्किल एक्सप्रेशन इस्तेमाल किए जा सकते हैं. इसलिए, यह अंतर करना ज़रूरी हो सकता है कि कोई वैल्यू, फ़ील्ड को दिखाती है या कॉन्स्टेंट को. यह उदाहरण देखें:

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

val pipeline = db.pipeline()
    .collection("cities")
    .where(field("name").equal(constant("Toronto")))

Java

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")))
)

स्टेज बनाने की सेवा

इनपुट स्टेज

इनपुट स्टेज, क्वेरी की पहली स्टेज को दिखाती है. इससे उन दस्तावेज़ों का शुरुआती सेट तय होता है जिनके लिए क्वेरी की जा रही है. पाइपलाइन क्वेरी के लिए, यह मौजूदा क्वेरी की तरह ही होती है. इसमें ज़्यादातर क्वेरी, collection(...) या collection_group(...) स्टेज से शुरू होती हैं. दो नई इनपुट स्टेज database() और documents(...) हैं. इनमें database() की मदद से, डेटाबेस में मौजूद सभी दस्तावेज़ों को वापस लाया जा सकता है. वहीं, documents(...), बैच रीड की तरह काम करता है.

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

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

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()
)

अन्य सभी चरणों की तरह, इनपुट चरणों से मिले नतीजों का क्रम स्थिर नहीं होता. अगर आपको किसी खास क्रम में नतीजे चाहिए, तो हमेशा sort(...) ऑपरेटर जोड़ें.

कहां

where(...) स्टेज, पिछले स्टेज से जनरेट किए गए दस्तावेज़ों पर फ़िल्टर करने की सुविधा देता है. साथ ही, यह मौजूदा क्वेरी के लिए "where" सिंटैक्स को दिखाता है. जिस दस्तावेज़ में दिया गया एक्सप्रेशन, true के अलावा कोई और वैल्यू दिखाता है उसे खोज के नतीजों से हटा दिया जाता है.

एक से ज़्यादा where(...) स्टेटमेंट को एक साथ जोड़ा जा सकता है. साथ ही, इन्हें and(...) एक्सप्रेशन के तौर पर इस्तेमाल किया जा सकता है. उदाहरण के लिए, यहां दी गई दो क्वेरी लॉजिक के हिसाब से एक जैसी हैं और इनका इस्तेमाल एक-दूसरे की जगह किया जा सकता है.

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

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

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()
)

फ़ील्ड चुनें / जोड़ें और हटाएं

select(...), add_fields(...), और remove_fields(...), इन सभी की मदद से, पिछली स्टेज से मिले फ़ील्ड में बदलाव किया जा सकता है. इन तीनों को आम तौर पर प्रोजेक्शन-स्टाइल वाले स्टेज कहा जाता है.

select(...) और add_fields(...) की मदद से, उपयोगकर्ता की ओर से दिए गए फ़ील्ड के नाम के लिए, किसी एक्सप्रेशन का नतीजा तय किया जा सकता है. गड़बड़ी वाले एक्सप्रेशन से null वैल्यू मिलती है. select(...) सिर्फ़ उन दस्तावेज़ों को दिखाएगा जिनमें फ़ील्ड के नाम तय किए गए हैं. वहीं, add_fields(...) पिछली स्टेज के स्कीमा को बढ़ाता है. इससे, एक जैसे फ़ील्ड के नाम वाली वैल्यू बदल सकती हैं.

remove_fields(...) की मदद से, पिछली स्टेज से हटाए जाने वाले फ़ील्ड का सेट तय किया जा सकता है. ऐसे फ़ील्ड के नाम तय करना जो मौजूद नहीं हैं, कोई कार्रवाई नहीं है.

नीचे दिया गया जवाब में शामिल किए जाने वाले फ़ील्ड सीमित करें सेक्शन देखें. हालांकि, आम तौर पर इस तरह के स्टेज का इस्तेमाल करके, नतीजे को सिर्फ़ उन फ़ील्ड तक सीमित किया जा सकता है जिनकी क्लाइंट को ज़रूरत होती है. इससे ज़्यादातर क्वेरी के लिए लागत और इंतज़ार का समय कम करने में मदद मिलती है.

एग्रीगेट / खास

aggregate(...) स्टेज की मदद से, इनपुट दस्तावेज़ों पर कई तरह के एग्रीगेशन किए जा सकते हैं. डिफ़ॉल्ट रूप से, सभी दस्तावेज़ों को एक साथ इकट्ठा किया जाता है. हालांकि, grouping आर्ग्युमेंट दिया जा सकता है. इससे इनपुट दस्तावेज़ों को अलग-अलग बकेट में इकट्ठा किया जा सकता है.

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

val results = db.pipeline()
    .collection("books")
    .aggregate(
        AggregateStage
            .withAccumulators(AggregateFunction.average("rating").alias("avg_rating"))
            .withGroups(field("genre"))
    )
    .execute()

Java

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()
)

अगर groupings तय नहीं किया जाता है, तो इस स्टेज में सिर्फ़ एक दस्तावेज़ जनरेट होगा. अगर groupings तय किया जाता है, तो groupings की वैल्यू के हर यूनीक कॉम्बिनेशन के लिए एक दस्तावेज़ जनरेट होगा.

distinct(...) स्टेज, एग्रीगेशन ऑपरेटर का आसान वर्शन है. इसकी मदद से, सिर्फ़ यूनीक groupings जनरेट किए जा सकते हैं. इसके लिए, किसी भी एक्युमुलेटर की ज़रूरत नहीं होती. अन्य सभी मामलों में, यह aggregate(...) की तरह ही काम करता है. यहां एक उदाहरण दिया गया है:

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

val results = db.pipeline()
    .collection("books")
    .distinct(
        field("author").toUpper().alias("author"),
        field("genre")
    )
    .execute()

Java

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()
)

फ़ंक्शन

फ़ंक्शन, एक्सप्रेशन और जटिल क्वेरी बनाने के लिए ज़रूरी होते हैं. उदाहरणों के साथ फ़ंक्शन की पूरी सूची देखने के लिए, फ़ंक्शन का रेफ़रंस देखें. हम आपको याद दिला दें कि किसी सामान्य क्वेरी का स्ट्रक्चर इस तरह का होता है:

क्वेरी में चरणों और फ़ंक्शन को दिखाने वाला उदाहरण

कई चरणों में ऐसे एक्सप्रेशन स्वीकार किए जाते हैं जिनमें एक या उससे ज़्यादा फ़ंक्शन शामिल होते हैं. फ़ंक्शन का सबसे ज़्यादा इस्तेमाल, where(...) और select(...)स्टेज में किया जाता है. दो मुख्य तरह के फ़ंक्शन होते हैं, जिनके बारे में आपको पता होना चाहिए:

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

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

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()
)

सीमाएं

ज़्यादातर मामलों में, Enterprise Edition में क्वेरी के आकार पर कोई पाबंदी नहीं होती. दूसरे शब्दों में कहें, तो IN या OR क्वेरी में वैल्यू की संख्या सीमित नहीं होती. इसके बजाय, आपको दो मुख्य सीमाओं के बारे में पता होना चाहिए:

  • समयसीमा: 60 सेकंड (स्टैंडर्ड एडिशन के जैसा).
  • मेमोरी का इस्तेमाल: क्वेरी को एक्ज़ीक्यूट करने के दौरान, मेटेरियलाइज़ किए गए डेटा के लिए 128 MiB की सीमा.

गड़बड़ियां

कई वजहों से, आपको क्वेरी पूरी न होने की समस्या आ सकती है. सामान्य गड़बड़ियों और उनसे जुड़ी कार्रवाई के बारे में जानने के लिए, यहां दिए गए लिंक पर क्लिक करें:

गड़बड़ी कोड कार्रवाई
DEADLINE_EXCEEDED आपकी क्वेरी को पूरा होने में 60 सेकंड से ज़्यादा समय लग रहा है. इसलिए, इसे और ऑप्टिमाइज़ करने की ज़रूरत है. सलाह के लिए, परफ़ॉर्मेंस सेक्शन देखें. अगर आपको समस्या की वजह पता नहीं चल पा रही है, तो टीम से संपर्क करें.
RESOURCE_EXHAUSTED आपकी क्वेरी, मेमोरी की तय सीमा से ज़्यादा है. इसलिए, इसे और ऑप्टिमाइज़ करने की ज़रूरत है. सलाह के लिए, परफ़ॉर्मेंस सेक्शन देखें. अगर आपको समस्या की वजह पता नहीं चल पा रही है, तो टीम से संपर्क करें.
INTERNAL सहायता पाने के लिए, टीम से संपर्क करें.

परफ़ॉर्मेंस

मौजूदा क्वेरी के उलट, पाइपलाइन क्वेरी के लिए यह ज़रूरी नहीं है कि इंडेक्स हमेशा मौजूद हो. इसका मतलब है कि किसी क्वेरी में, मौजूदा क्वेरी की तुलना में ज़्यादा समय लग सकता है. मौजूदा क्वेरी में, इंडेक्स मौजूद न होने की गड़बड़ी FAILED_PRECONDITION की वजह से तुरंत जवाब नहीं मिलता. पाइपलाइन क्वेरी की परफ़ॉर्मेंस को बेहतर बनाने के लिए, ये तरीके अपनाएं.

इंडेक्स बनाना

इस्तेमाल किया गया इंडेक्स

क्वेरी के बारे में जानकारी देने वाली सुविधा से, यह पता लगाया जा सकता है कि आपकी क्वेरी को इंडेक्स से दिखाया जा रहा है या टेबल स्कैन जैसी कम असरदार कार्रवाई पर वापस लाया जा रहा है. अगर आपकी क्वेरी के नतीजे इंडेक्स से पूरी तरह नहीं मिल रहे हैं, तो निर्देशों का पालन करके इंडेक्स बनाया जा सकता है.

इंडेक्स बनाना

इंडेक्स बनाने के लिए, इंडेक्स मैनेज करने से जुड़े मौजूदा दस्तावेज़ को पढ़ें. इंडेक्स बनाने से पहले, Firestore में इंडेक्स के सबसे सही तरीके जान लें. यह पक्का करने के लिए कि आपकी क्वेरी इंडेक्स का इस्तेमाल कर सके, फ़ील्ड के साथ इंडेक्स बनाने के लिए सबसे सही तरीके अपनाएं. फ़ील्ड को इस क्रम में रखें:

  1. ऐसे सभी फ़ील्ड जिनका इस्तेमाल समानता वाले फ़िल्टर में किया जाएगा (किसी भी क्रम में)
  2. वे सभी फ़ील्ड जिन्हें एक ही क्रम में क्रम से लगाया जाएगा
  3. क्वेरी की शर्तों के हिसाब से घटते क्रम में, रेंज या असमानता वाले फ़िल्टर में इस्तेमाल किए जाने वाले फ़ील्ड

उदाहरण के लिए, इस क्वेरी के लिए,

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

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

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()
)

सुझाया गया इंडेक्स, (genre [...], published DESC, avg_rating DESC). के लिए books पर कलेक्शन स्कोप इंडेक्स है

इंडेक्स डेंसिटी

Cloud Firestore, स्पार्स और नॉन-स्पार्स इंडेक्स के साथ काम करता है. ज़्यादा जानकारी के लिए, इंडेक्स डेंसिटी देखें.

कवर की गई क्वेरी + सेकंडरी इंडेक्स

अगर लौटाए जा रहे सभी फ़ील्ड, सेकंडरी इंडेक्स में मौजूद हैं, तो Firestore पूरे दस्तावेज़ को फ़ेच करने के बजाय, सिर्फ़ इंडेक्स से नतीजे दिखा सकता है. इससे आम तौर पर, लेटेन्सी (और लागत) में काफ़ी सुधार होता है. यहाँ दी गई सैंपल क्वेरी का इस्तेमाल करके:

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

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

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()
)

अगर डेटाबेस में books के लिए (category [...], title [...], author [...]) पर पहले से ही कलेक्शन स्कोप इंडेक्स मौजूद है, तो यह मुख्य दस्तावेज़ों से कुछ भी फ़ेच करने से बच सकता है. इस मामले में, इंडेक्स में मौजूद क्रम से कोई फ़र्क़ नहीं पड़ता. [...] का इस्तेमाल यह बताने के लिए किया जाता है.

जवाब में शामिल किए जाने वाले फ़ील्ड सीमित करना

डिफ़ॉल्ट रूप से, Firestore क्वेरी किसी दस्तावेज़ के सभी फ़ील्ड दिखाती है. यह पारंपरिक सिस्टम में SELECT * के जैसा होता है. हालांकि, अगर आपके ऐप्लिकेशन को सिर्फ़ कुछ फ़ील्ड की ज़रूरत है, तो select(...) या restrict(...) चरणों का इस्तेमाल करके, इस फ़िल्टरिंग को सर्वर साइड पर पुश किया जा सकता है. इससे जवाब का साइज़ कम हो जाएगा. साथ ही, नेटवर्क से बाहर निकलने की लागत कम हो जाएगी और जवाब मिलने में कम समय लगेगा.

समस्या निवारण टूल

क्वेरी की व्याख्या करना

क्वेरी के बारे में जानकारी देने वाली सुविधा की मदद से, आपको एक्ज़ीक्यूशन मेट्रिक और इस्तेमाल किए गए इंडेक्स के बारे में जानकारी मिलती है.

मेट्रिक

अगर पाइपलाइन क्वेरी को मौजूदा Firestore मेट्रिक के साथ पूरी तरह से इंटिग्रेट किया गया है.

पहले से मालूम समस्याएं / सीमाएं

खास इंडेक्स

पाइपलाइन क्वेरी में, फ़िलहाल मौजूदा array-contains और vector इंडेक्स टाइप का इस्तेमाल नहीं किया जा सकता. Firestore, इस तरह की क्वेरी को सिर्फ़ अस्वीकार करने के बजाय, मौजूदा अन्य ascending और descending इंडेक्स का इस्तेमाल करने की कोशिश करेगा. ऐसा माना जाता है कि इस वजह से, प्राइवेट प्रीव्यू के दौरान इस तरह के array_contains या find_nearest एक्सप्रेशन वाली पाइपलाइन क्वेरी, मौजूदा क्वेरी की तुलना में धीमी होंगी.

खोज नतीजों को पेजों में बांटना

निजी पूर्वावलोकन के दौरान, नतीजों के सेट में आसानी से पेज नंबर बदलने की सुविधा उपलब्ध नहीं है. इसके लिए, यहां दिखाए गए तरीके से where(...) और sort(...) के बराबर चरणों को एक साथ जोड़ा जा सकता है.

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

// 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

// 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())
)

एम्युलेटर से जुड़ी सहायता

एम्युलेटर में फ़िलहाल पाइपलाइन क्वेरी का इस्तेमाल नहीं किया जा सकता.

रीयलटाइम और ऑफ़लाइन सहायता

पाइपलाइन क्वेरी के लिए, अभी रीयलटाइम और ऑफ़लाइन मोड में काम करने की सुविधाएं उपलब्ध नहीं हैं.

आगे क्या करना है