Firestore Pipeline की कार्रवाइयों की मदद से डेटा पाना

बैकग्राउंड

पाइपलाइन ऑपरेशन, Cloud 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 इंडेक्स मौजूद न होने की वजह से, मौजूदा क्वेरी तुरंत फ़ेल हो जाती है. पाइपलाइन ऑपरेशन की परफ़ॉर्मेंस को बेहतर बनाने के लिए, ये तरीके अपनाए जा सकते हैं.

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

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

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

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

इंडेक्स बनाने के लिए, इंडेक्स मैनेज करने से जुड़े मौजूदा दस्तावेज़ को पढ़ा जा सकता है. इंडेक्स बनाने से पहले, Cloud 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, स्पार्स और नॉन-स्पार्स इंडेक्स के साथ काम करता है. ज़्यादा जानकारी के लिए, इंडेक्स डेंसिटी देखें.

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

अगर जवाब में शामिल किए गए सभी फ़ील्ड, सेकंडरी इंडेक्स में मौजूद हैं, तो Cloud 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 [...]) पर पहले से ही कलेक्शन स्कोप इंडेक्स मौजूद है, तो यह मुख्य दस्तावेज़ों से कुछ भी फ़ेच करने से बच सकता है. इस मामले में, इंडेक्स में मौजूद क्रम से कोई फ़र्क़ नहीं पड़ता. [...] का इस्तेमाल यह बताने के लिए किया जाता है.

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

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

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

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

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

मेट्रिक

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

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

खास इंडेक्स

पाइपलाइन ऑपरेशन, फ़िलहाल मौजूदा array-contains और vector इंडेक्स टाइप के साथ काम नहीं करते. इस तरह की क्वेरी को सिर्फ़ अस्वीकार करने के बजाय, Cloud 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())
)

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

एम्युलेटर में, फ़िलहाल पाइपलाइन ऑपरेशन काम नहीं करते.

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

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

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