ข้อมูลเบื้องต้น
การค้นหาแบบไปป์ไลน์เป็นอินเทอร์เฟซการค้นหาใหม่สำหรับ Firestore ซึ่งมีฟังก์ชันการทำงานของคำค้นหาขั้นสูง รวมถึงนิพจน์ที่ซับซ้อน นอกจากนี้ยังรองรับฟังก์ชันใหม่ๆ อีกมากมาย เช่น min, max, substring, regex_match และ array_contains_all
การค้นหาไปป์ไลน์ยังช่วยให้การสร้างดัชนีเป็นแบบไม่บังคับโดยสมบูรณ์ ซึ่งช่วยเพิ่มประสิทธิภาพ
กระบวนการพัฒนาการค้นหาใหม่ๆ นอกจากนี้ การค้นหาแบบไปป์ไลน์ยังช่วยลดข้อจำกัดหลายอย่างเกี่ยวกับรูปร่างของการค้นหา ทำให้คุณระบุการค้นหา in หรือ or ขนาดใหญ่ได้
เริ่มต้นใช้งาน
หากต้องการติดตั้งและเริ่มต้น SDK ของไคลเอ็นต์ โปรดดูวิธีการในคู่มือเริ่มต้นใช้งาน
ไวยากรณ์
ส่วนต่อไปนี้จะให้ภาพรวมของไวยากรณ์สำหรับคำค้นหาแบบไปป์ไลน์
แนวคิด
ความแตกต่างที่สำคัญอย่างหนึ่งของคำค้นหาแบบไปป์ไลน์คือการนำการจัดลำดับ "ขั้นตอน" ที่ชัดเจนมาใช้ ซึ่งช่วยให้สามารถแสดงคำค้นหาที่ซับซ้อนมากขึ้นได้ อย่างไรก็ตาม การดำเนินการนี้ถือเป็นการเบี่ยงเบนที่สำคัญจากอินเทอร์เฟซการค้นหาที่มีอยู่ ซึ่งมีการจัดลำดับขั้นตอนโดยนัย ลองดูตัวอย่างการค้นหาแบบไปป์ไลน์ต่อไปนี้
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()
โครงสร้าง
เมื่อสร้างการค้นหา Pipeline คุณควรทำความเข้าใจคำศัพท์ 2-3 คำ ได้แก่ สเตจ นิพจน์ และฟังก์ชัน

ขั้นตอน: ไปป์ไลน์อาจประกอบด้วยขั้นตอนอย่างน้อย 1 ขั้นตอน ตามตรรกะแล้ว สิ่งเหล่านี้แสดงถึงชุดขั้นตอน (หรือระยะ) ที่ใช้ในการดำเนินการค้นหา หมายเหตุ: ในทางปฏิบัติ ระบบอาจดำเนินการในแต่ละขั้นตอนแบบไม่เรียงตามลำดับเพื่อปรับปรุงประสิทธิภาพ อย่างไรก็ตาม การดำเนินการนี้จะไม่แก้ไขเจตนาหรือความถูกต้องของคำค้นหา
นิพจน์: ขั้นตอนมักจะยอมรับนิพจน์ที่ช่วยให้คุณแสดงคำค้นหาที่ซับซ้อนมากขึ้นได้ นิพจน์อาจเป็นนิพจน์อย่างง่ายที่ประกอบด้วยฟังก์ชันเดียว เช่น 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(...) อินพุตใหม่ 2 ขั้นตอนคือ 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(...) ได้ ตัวอย่างเช่น คำค้นหา 2 รายการต่อไปนี้มีความหมายเหมือนกันในเชิงตรรกะและใช้แทนกันได้
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(...) ช่วยให้คุณ
แก้ไขฟิลด์ที่ส่งคืนจากขั้นตอนก่อนหน้าได้ โดยทั่วไปแล้วทั้ง 3 รูปแบบนี้
เรียกว่าเวทีสไตล์การฉายภาพ
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
distinct(...)สเตจgroupingsเป็นตัวดำเนินการรวบรวมที่เรียบง่ายซึ่งช่วยให้สร้างเฉพาะ 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() )
ฟังก์ชัน
ฟังก์ชันเป็นองค์ประกอบพื้นฐานสำหรับการสร้างนิพจน์และการค้นหาที่ซับซ้อน ดูรายการฟังก์ชันทั้งหมดพร้อมตัวอย่างได้ในข้อมูลอ้างอิงของฟังก์ชัน โปรดทราบว่าโครงสร้างของการค้นหาทั่วไปมีลักษณะดังนี้

หลายขั้นตอนยอมรับนิพจน์ที่มีฟังก์ชันอย่างน้อย 1 รายการ การใช้งานฟังก์ชันที่พบบ่อยที่สุดจะอยู่ในขั้นตอนwhere(...)และselect(...) ฟังก์ชันหลักๆ ที่คุณควรทราบมี 2 ประเภท ดังนี้
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 แต่คุณควรทราบถึงข้อจำกัดหลัก 2 อย่างต่อไปนี้
- กำหนดเวลา: 60 วินาที (เหมือนกับรุ่นมาตรฐาน)
- การใช้หน่วยความจำ: จำกัด 128 MiB สำหรับปริมาณข้อมูลที่สร้างขึ้นระหว่างการดำเนินการค้นหา
ข้อผิดพลาด
คุณอาจพบคำค้นหาที่ไม่สำเร็จเนื่องจากสาเหตุหลายประการ ต่อไปนี้คือลิงก์ไปยังข้อผิดพลาดที่พบบ่อยและการดำเนินการที่เกี่ยวข้องที่คุณทำได้
| รหัสข้อผิดพลาด | การดำเนินการ |
DEADLINE_EXCEEDED
|
การค้นหาที่คุณกำลังดำเนินการเกินกำหนดเวลา 60 วินาทีและต้องมีการเพิ่มประสิทธิภาพเพิ่มเติม ดูเคล็ดลับได้ที่ส่วนประสิทธิภาพ หากระบุสาเหตุของปัญหาไม่ได้ โปรดติดต่อทีม |
RESOURCE_EXHAUSTED
|
คําค้นหาที่คุณเรียกใช้เกินขีดจํากัดหน่วยความจําและต้องมีการเพิ่มประสิทธิภาพเพิ่มเติม ดูเคล็ดลับได้ที่ส่วนประสิทธิภาพ หากระบุสาเหตุของปัญหาไม่ได้ โปรดติดต่อทีม |
INTERNAL
|
ติดต่อทีมเพื่อขอรับการสนับสนุน |
ประสิทธิภาพ
ข้อความค้นหาไปป์ไลน์ไม่จำเป็นต้องมีดัชนีเสมอไป ซึ่งต่างจากข้อความค้นหาที่มีอยู่ ซึ่งหมายความว่าคำค้นหาอาจมีเวลาในการตอบสนองสูงกว่าคำค้นหาที่มีอยู่ ซึ่งจะล้มเหลวทันทีเนื่องจากข้อผิดพลาด FAILED_PRECONDITION ไม่มีดัชนี คุณสามารถทำตามขั้นตอน 2-3 ขั้นตอนเพื่อปรับปรุงประสิทธิภาพของคำค้นหาแบบไปป์ไลน์
สร้างดัชนี
ดัชนีที่ใช้
คำอธิบายการค้นหาช่วยให้คุณระบุได้ว่าการค้นหาของคุณได้รับการแสดงผลโดยดัชนีหรือกลับไปใช้การดำเนินการที่มีประสิทธิภาพน้อยกว่า เช่น การสแกนตาราง หากคำค้นหาไม่ได้แสดงผลจากดัชนีทั้งหมด คุณสามารถสร้างดัชนีได้โดยทำตามวิธีการ
การสร้างดัชนี
คุณสามารถทำตามเอกสารประกอบการจัดการดัชนีที่มีอยู่เพื่อสร้างดัชนี ก่อนสร้างดัชนี โปรดทำความคุ้นเคยกับแนวทางปฏิบัติแนะนำทั่วไปสำหรับดัชนีใน Firestore โปรดทำตามแนวทางปฏิบัติแนะนำในการสร้างดัชนีที่มีฟิลด์ตามลำดับต่อไปนี้เพื่อให้แน่ใจว่าคำค้นหาใช้ประโยชน์จากดัชนีได้
- ฟิลด์ทั้งหมดที่จะใช้ในตัวกรองความเท่ากัน (ในลำดับใดก็ได้)
- ฟิลด์ทั้งหมดที่จะจัดเรียง (ในลำดับเดียวกัน)
- ฟิลด์ที่จะใช้ในตัวกรองช่วงหรือตัวกรองความไม่เท่ากันตามลำดับการลดลงของความสามารถในการเลือกข้อจำกัดของการค้นหา
เช่น สำหรับคำค้นหาต่อไปนี้
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() )
ดัชนีที่แนะนำคือดัชนีขอบเขตคอลเล็กชันใน books สำหรับ (genre [...], published DESC, avg_rating DESC).
ความหนาแน่นของดัชนี
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(...) เพื่อส่งการกรองนี้ไปยังฝั่งเซิร์ฟเวอร์ได้ ซึ่งจะช่วยลดทั้งขนาดการตอบสนอง (ลดต้นทุนขาออกจากเครือข่าย) และปรับปรุงเวลาในการตอบสนอง
เครื่องมือแก้ปัญหา
อธิบายการค้นหา
Query Explain ช่วยให้คุณมองเห็นเมตริกการดำเนินการและรายละเอียดเกี่ยวกับดัชนีที่ใช้
เมตริก
คำค้นหาในไปป์ไลน์หากผสานรวมกับเมตริก Firestore ที่มีอยู่โดยสมบูรณ์
ปัญหา / ข้อจำกัดที่ทราบ
ดัชนีเฉพาะทาง
การค้นหาไปป์ไลน์ยังไม่รองรับarray-containsและvector ประเภทดัชนีที่มีอยู่ Firestore จะพยายามใช้ดัชนี ascending & descending อื่นๆ ที่มีอยู่แทนที่จะปฏิเสธคำค้นหาดังกล่าว คาดว่าในระหว่างช่วงตัวอย่างแบบส่วนตัว คำค้นหา Pipeline ที่มีนิพจน์ 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()) )
การสนับสนุนโปรแกรมจำลอง
โปรแกรมจำลองยังไม่รองรับการค้นหาแบบไปป์ไลน์
การสนับสนุนแบบเรียลไทม์และแบบออฟไลน์
การค้นหาไปป์ไลน์ยังไม่มีความสามารถแบบเรียลไทม์และออฟไลน์
ขั้นตอนถัดไป
- เริ่มสำรวจเอกสารอ้างอิงเกี่ยวกับฟังก์ชันและสเตจ