Nhận dữ liệu bằng các thao tác trong quy trình Firestore

Thông tin khái quát

Các hoạt động của quy trình cung cấp một giao diện truy vấn mới cho Cloud Firestore hỗ trợ chức năng truy vấn nâng cao và các biểu thức phức tạp. Giao diện này giới thiệu nhiều hàm mới, bao gồm min(...), max(...), substring(...), regex_match(...)array_contains_all(...), cũng như các giai đoạn để có thể thực hiện các phép biến đổi phức tạp.

Bắt đầu

Để cài đặt và khởi chạy SDK ứng dụng, hãy tham khảo hướng dẫn trong các bài viết sau:

Cú pháp

Các phần sau đây cung cấp thông tin tổng quan về cú pháp cho các hoạt động của quy trình.

Khái niệm

Một điểm khác biệt đáng chú ý với các hoạt động của quy trình là việc giới thiệu thứ tự "giai đoạn" rõ ràng. Điều này giúp bạn có thể biểu thị các truy vấn phức tạp hơn. Tuy nhiên, đây là một điểm khác biệt đáng chú ý so với giao diện truy vấn hiện có bằng cách sử dụng các hoạt động cốt lõi, trong đó thứ tự của các giai đoạn được ngụ ý. Hãy xem ví dụ sau về các hoạt động của quy trình:

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

Khởi chạy

Các hoạt động của quy trình có một cú pháp rất quen thuộc đến từ các truy vấn Cloud Firestore hiện có. Để bắt đầu, bạn hãy khởi chạy một truy vấn bằng cách viết như sau:

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

Cấu trúc

Có một vài thuật ngữ quan trọng mà bạn cần hiểu khi tạo các hoạt động của quy trình: giai đoạn, biểu thức và hàm.

Ví dụ minh hoạ các giai đoạn và biểu thức trong một truy vấn

Giai đoạn: Một quy trình có thể bao gồm một hoặc nhiều giai đoạn. Về mặt logic, các giai đoạn này đại diện cho chuỗi các bước (hoặc giai đoạn) được thực hiện để thực thi truy vấn. Lưu ý: Trong thực tế, các giai đoạn có thể được thực thi không theo thứ tự để cải thiện hiệu suất. Tuy nhiên, điều này không làm thay đổi ý định hoặc tính chính xác của truy vấn.

Biểu thức: Các giai đoạn thường chấp nhận một biểu thức cho phép bạn biểu thị các truy vấn phức tạp hơn. Biểu thức có thể đơn giản và bao gồm một hàm duy nhất như eq("a", 1). Bạn cũng có thể biểu thị các biểu thức phức tạp hơn bằng cách lồng các biểu thức như and(eq("a", 1), eq("b", 2)).

Tham chiếu trường so với tham chiếu hằng số

Các hoạt động của quy trình hỗ trợ các biểu thức phức tạp. Do đó, bạn có thể cần phân biệt xem một giá trị đại diện cho trường hay hằng số. Hãy xem ví dụ sau đây:

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

Giai đoạn

Giai đoạn đầu vào

Giai đoạn đầu vào đại diện cho giai đoạn đầu tiên của một truy vấn. Giai đoạn này xác định tập hợp tài liệu ban đầu mà bạn đang truy vấn. Đối với các hoạt động của quy trình, điều này phần lớn tương tự như các truy vấn hiện có, trong đó hầu hết các truy vấn bắt đầu bằng giai đoạn collection(...) hoặc collection_group(...). Hai giai đoạn đầu vào mới là database()documents(...), trong đó database() cho phép trả về tất cả tài liệu trong cơ sở dữ liệu, còn documents(...) hoạt động giống như một lần đọc hàng loạt.

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

Giống như tất cả các giai đoạn khác, thứ tự kết quả từ các giai đoạn đầu vào này không ổn định. Bạn phải luôn thêm toán tử sort(...) nếu muốn có một thứ tự cụ thể.

Địa điểm

Giai đoạn where(...) hoạt động như một thao tác lọc truyền thống trên các tài liệu được tạo từ giai đoạn trước và hầu hết phản ánh cú pháp "where" hiện có cho các truy vấn hiện có. Mọi tài liệu mà một biểu thức nhất định đánh giá thành giá trị không phải là true đều bị lọc ra khỏi các tài liệu được trả về.

Bạn có thể xâu chuỗi nhiều câu lệnh where(...) với nhau và hoạt động như một biểu thức and(...). Ví dụ: hai truy vấn sau đây tương đương về mặt logic và có thể được sử dụng thay thế cho nhau.

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

Chọn / Thêm và xoá trường

select(...), add_fields(...)remove_fields(...) đều cho phép bạn sửa đổi các trường được trả về từ giai đoạn trước. Ba trường này thường được gọi là các giai đoạn theo kiểu chiếu.

select(...)add_fields(...) cho phép bạn chỉ định kết quả của một biểu thức cho tên trường do người dùng cung cấp. Một biểu thức dẫn đến lỗi sẽ dẫn đến giá trị null. select(...) sẽ chỉ trả về các tài liệu có tên trường được chỉ định, trong khi add_fields(...) mở rộng giản đồ của giai đoạn trước (có thể ghi đè các giá trị có tên trường giống hệt nhau).

remove_fields(...) cho phép chỉ định một tập hợp các trường cần xoá khỏi giai đoạn trước. Việc chỉ định tên trường không tồn tại là một thao tác không có tác dụng.

Hãy xem phần Giới hạn các trường cần trả về bên dưới, nhưng nói chung, việc sử dụng một giai đoạn như vậy để giới hạn kết quả chỉ cho các trường cần thiết trong ứng dụng sẽ giúp giảm chi phí và độ trễ cho hầu hết các truy vấn.

Tổng hợp / Phân biệt

Giai đoạn aggregate(...) cho phép bạn thực hiện một loạt các phép tổng hợp trên các tài liệu đầu vào. Theo mặc định, tất cả các tài liệu được tổng hợp cùng nhau, nhưng bạn có thể cung cấp đối số grouping không bắt buộc, cho phép các tài liệu đầu vào được tổng hợp thành các nhóm khác nhau.

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

Khi bạn không chỉ định groupings, giai đoạn này sẽ chỉ tạo một tài liệu duy nhất, nếu không, một tài liệu sẽ được tạo cho mỗi tổ hợp giá trị groupings riêng biệt.

Giai đoạn distinct(...) là một toán tử tổng hợp đơn giản cho phép chỉ tạo groupings riêng biệt mà không có bất kỳ bộ tích luỹ nào. Giai đoạn này hoạt động giống hệt như aggregate(...) về mọi mặt khác. Dưới đây là một ví dụ:

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

Hàm

Hàm là một thành phần để tạo biểu thức và truy vấn phức tạp. Để biết danh sách đầy đủ các hàm có ví dụ, hãy tham khảo Tài liệu tham khảo về hàm. Để nhắc lại nhanh, hãy xem xét cấu trúc của một truy vấn điển hình:

Ví dụ minh hoạ các giai đoạn và hàm trong một truy vấn

Nhiều giai đoạn chấp nhận các biểu thức chứa một hoặc nhiều hàm. Bạn sẽ tìm thấy cách sử dụng hàm phổ biến nhất trong các giai đoạn where(...)select(...). Có 2 loại hàm chính mà bạn nên làm quen:

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

Giới hạn

Phần lớn, phiên bản Enterprise không áp đặt giới hạn về hình dạng của truy vấn. Nói cách khác, bạn không bị giới hạn ở một số lượng nhỏ giá trị trong truy vấn IN hoặc OR. Thay vào đó, có 2 giới hạn chính mà bạn cần lưu ý:

  • Thời hạn: 60 giây (giống như phiên bản Standard).
  • Mức sử dụng bộ nhớ: Giới hạn 128 MiB về lượng dữ liệu được hiện thực hoá trong quá trình thực thi truy vấn.

Lỗi

Bạn có thể gặp phải các truy vấn không thành công vì một số lý do. Dưới đây là đường liên kết đến các lỗi thường gặp và hành động liên quan mà bạn có thể thực hiện:

Mã lỗi Hành động
DEADLINE_EXCEEDED Truy vấn mà bạn đang thực thi vượt quá thời hạn 60 giây và cần được tối ưu hoá thêm. Hãy xem phần hiệu suất để biết các mẹo. Nếu bạn không thể xác định nguyên nhân gốc rễ của vấn đề, hãy liên hệ với nhóm.
RESOURCE_EXHAUSTED Truy vấn mà bạn đang thực thi vượt quá giới hạn bộ nhớ và cần được tối ưu hoá thêm. Hãy xem phần hiệu suất để biết các mẹo. Nếu bạn không thể xác định nguyên nhân gốc rễ của vấn đề, hãy liên hệ với nhóm.
INTERNAL Liên hệ với nhóm để được hỗ trợ.

Hiệu suất

Không giống như các truy vấn hiện có, các hoạt động của quy trình không yêu cầu phải luôn có chỉ mục. Điều này có nghĩa là một truy vấn có thể có độ trễ cao hơn so với các truy vấn hiện có, vốn sẽ thất bại ngay lập tức với lỗi chỉ mục FAILED_PRECONDITION bị thiếu. Để cải thiện hiệu quả của các hoạt động của pipeline, bạn có thể thực hiện một số bước.

Tạo chỉ mục

Chỉ mục đã sử dụng

Tính năng giải thích truy vấn cho phép bạn xác định xem truy vấn của mình đang được một chỉ mục phân phát hay đang quay lại một thao tác kém hiệu quả hơn như quét bảng. Nếu truy vấn của bạn không được phân phát đầy đủ từ một chỉ mục, bạn có thể tạo một chỉ mục bằng cách làm theo hướng dẫn.

Tạo chỉ mục

Bạn có thể làm theo tài liệu hiện có về quản lý chỉ mục để tạo chỉ mục. Trước khi tạo chỉ mục, hãy làm quen với các phương pháp hay nhất chung về chỉ mục trong Cloud Firestore. Để đảm bảo truy vấn của bạn có thể tận dụng chỉ mục, hãy làm theo các phương pháp hay nhất để tạo chỉ mục có các trường theo thứ tự sau:

  1. Tất cả các trường sẽ được sử dụng trong bộ lọc đẳng thức (theo bất kỳ thứ tự nào)
  2. Tất cả các trường sẽ được sắp xếp (theo cùng một thứ tự)
  3. Các trường sẽ được sử dụng trong bộ lọc phạm vi hoặc bộ lọc bất đẳng thức theo thứ tự giảm dần của mức độ chọn lọc ràng buộc truy vấn

Ví dụ: đối với truy vấn sau,

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

Chỉ mục được đề xuất là chỉ mục phạm vi tập hợp trên books cho (genre [...], published DESC, avg_rating DESC).

Mật độ chỉ mục

Cloud Firestore hỗ trợ chỉ mục thưa và không thưa. Để biết thêm thông tin, xem Mật độ chỉ mục.

Truy vấn được bao phủ + Chỉ mục thứ cấp

Cloud Firestore có thể bỏ qua việc tìm nạp toàn bộ tài liệu và chỉ trả về kết quả từ chỉ mục nếu tất cả các trường được trả về đều có trong chỉ mục thứ cấp. Điều này thường dẫn đến việc cải thiện đáng kể độ trễ (và chi phí). Sử dụng truy vấn mẫu bên dưới:

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

Nếu cơ sở dữ liệu đã có chỉ mục phạm vi tập hợp trên books cho (category [...], title [...], author [...]), thì cơ sở dữ liệu đó có thể tránh tìm nạp bất kỳ nội dung nào từ chính các tài liệu chính. Trong trường hợp này, thứ tự trong chỉ mục không quan trọng, [...] được dùng để biểu thị điều đó.

Giới hạn các trường cần trả về

Theo mặc định, một Cloud Firestore truy vấn trả về tất cả các trường trong một tài liệu, tương tự như một SELECT * trong các hệ thống truyền thống. Tuy nhiên, nếu ứng dụng của bạn chỉ cần một tập hợp con các trường, thì bạn có thể sử dụng các giai đoạn select(...) hoặc restrict(...) để đẩy quá trình lọc này ở phía máy chủ. Điều này sẽ làm giảm cả kích thước phản hồi (giảm chi phí truyền dữ liệu ra khỏi mạng) cũng như cải thiện độ trễ.

Công cụ khắc phục sự cố

Giải thích truy vấn

Tính năng giải thích truy vấn cho phép bạn xem các chỉ số thực thi và thông tin chi tiết về các chỉ mục được sử dụng.

Chỉ số

Các hoạt động của quy trình nếu được tích hợp đầy đủ với các chỉ số Cloud Firestore hiện có.

Các vấn đề / hạn chế đã biết

Chỉ mục chuyên biệt

Các hoạt động của quy trình chưa hỗ trợ các loại chỉ mục array-contains & vector hiện có. Thay vì chỉ từ chối các truy vấn như vậy, Cloud Firestore sẽ cố gắng sử dụng các chỉ mục ascending & descending hiện có khác. Dự kiến trong quá trình xem trước riêng tư, các hoạt động của quy trình có các biểu thức array_contains hoặc find_nearest như vậy sẽ chậm hơn so với các biểu thức tương đương hiện có do điều này.

Đánh số trang

Chúng tôi không hỗ trợ tính năng dễ dàng phân trang trên một tập hợp kết quả trong quá trình xem trước riêng tư. Bạn có thể giải quyết vấn đề này bằng cách xâu chuỗi các giai đoạn where(...)sort(...) tương đương như minh hoạ bên dưới.

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

Hỗ trợ trình mô phỏng

Trình mô phỏng không hỗ trợ các hoạt động của quy trình.

Hỗ trợ theo thời gian thực và ngoại tuyến

Các hoạt động của quy trình chưa có các tính năng theo thời gian thực và ngoại tuyến.

Bước tiếp theo