คำอธิบาย
กำหนดตัวแปรชั่วคราวที่อ้างอิงได้ในขั้นตอนต่อๆ ไปของไปป์ไลน์
ระบบจะไม่รวมตัวแปรที่สร้างในขั้นตอน let(...) ไว้ในผลลัพธ์สุดท้าย
เว้นแต่จะมีการกำหนดตัวแปรดังกล่าวให้กับฟิลด์อย่างชัดแจ้งในขั้นตอนต่อมา (เช่น ใช้
add_fields(...) หรือ
select(...)) ซึ่งจะช่วยให้คุณลดความซับซ้อนของตรรกะที่ซับซ้อนได้ด้วย
การแบ่งตรรกะออกเป็นคอมโพเนนต์ขนาดเล็กที่นำกลับมาใช้ซ้ำได้โดยไม่ทำให้เอกสารเอาต์พุต
ดูรก ขั้นตอน let(...) มีประโยชน์อย่างยิ่งสำหรับ ไปป์ไลน์ย่อย
ที่สัมพันธ์กัน ซึ่งไปป์ไลน์ย่อยต้องอ้างอิงค่าจากขอบเขตของเอกสาร
หลัก
ตัวอย่าง
Node.js
const results = await db.pipeline()
.collection("/awards")
// `let(...)` referred to as `define(...)` in the Web SDK.
.define(rand().as("r"))
.addFields(
switchOn(
lessThan(variable("r"), 0.05), constant("rare"),
lessThan(variable("r"), 0.25), constant("uncommon"),
constant("common")).as("random_score"))
.execute();
พฤติกรรม
ตัวแปรเทียบกับฟิลด์
แม้ว่าฟิลด์ จะแสดงถึงข้อมูลที่จัดเก็บไว้ในเอกสาร แต่ตัวแปร เป็นค่าชั่วคราวที่มีอยู่เฉพาะในระหว่างการดำเนินการของไปป์ไลน์
| ฟิลด์ | ตัวแปร | |
|---|---|---|
| วัตถุประสงค์ | เข้าถึงหรือจัดเก็บฟิลด์ลงในเอกสาร | สร้างหรือเข้าถึงค่าชั่วคราวระหว่างการดำเนินการของไปป์ไลน์ |
| การใช้งาน SDK | field("name") |
variable("name") |
| ขอบเขต | เฉพาะเอกสารปัจจุบัน | รวมทั้งหมดสำหรับไปป์ไลน์และไปป์ไลน์ย่อย |
| ข้อมูลอ้างอิงที่ไม่ได้กำหนด | ประเมินเป็น absent |
สร้างข้อผิดพลาดขณะรันไทม์ |
ขอบเขต:
แม้ว่าฟิลด์จะมีขอบเขตเป็นเอกสารในเครื่อง แต่ตัวแปรจะกำหนดไว้ในขอบเขตที่แยกต่างหากและยังคงเข้าถึงได้ในทุกขั้นตอนจนกว่าจะถึงขั้นตอนแรกที่ "ผสาน" เอกสารหลายรายการเข้าด้วยกัน (เช่น
aggregate(...) หรือ
distinct(...)) ขั้นตอนที่ "ผสาน" เอกสารหลายรายการไม่อนุญาตให้ใช้ข้อมูลอ้างอิงตัวแปรหลังจากนั้น เนื่องจากเมื่อผสานผลลัพธ์ของขั้นตอนก่อนหน้าเข้าด้วยกันแล้ว ตัวแปรจะไม่มีค่าเดียวอีกต่อไป
สิ่งที่ควรทำ: อ้างอิงตัวแปรหลังจากกรองฟิลด์ของ เอกสาร
Node.js
const results = db.pipeline()
.collection("/awards")
.define(min(field("score").abs(), constant(100)).as("normalized_score"))
.select(field("__name__"), field("owner_id"))
// Successfully able to use the variable.
.where(variable("normalized_score").greaterThan(10))
.execute();
สิ่งที่ไม่ควรทำ: อ้างอิงตัวแปร หลังจาก การรวม
Node.js
const results = db.pipeline()
.collection("/awards")
.define(min(field("score").abs(), constant(100)).as("normalized_score"))
.aggregate({
accumulators: [ field("score").avg().as("avg_score") ],
groups: [ field("owner_id") ]
})
// Attempting to use the variable throws a request validation error.
.where(variable("normalized_score").greaterThan(10))
.execute();
ข้อมูลอ้างอิงที่ไม่ได้กำหนด:
แม้ว่าการอ้างอิงฟิลด์ที่ไม่ได้กำหนดจะทำได้ (และประเมินเป็น absent) แต่การพยายามอ้างอิงตัวแปรที่ไม่ได้กำหนดจะล้มเหลวระหว่างการตรวจสอบคำขอ ในแง่นี้ ข้อมูลอ้างอิงฟิลด์อาจมองได้ว่าเป็นการค้นหาในแผนที่ขณะรันไทม์ ในขณะที่ข้อมูลอ้างอิงตัวแปรจะคล้ายกับตัวแปรในภาษาโปรแกรมที่คอมไพล์แบบคงที่มากกว่า
ขอบเขตรวมทั้งหมดและคําค้นหาย่อย
ตัวแปรมีความสำคัญอย่างยิ่งเมื่อทำงานกับไปป์ไลน์ที่ซ้อนกัน ไปป์ไลน์ย่อยจะดำเนินการในขอบเขตของตัวเองและเข้าถึงได้เฉพาะฟิลด์ของเอกสารที่กำลังประมวลผลเท่านั้น หากต้องการใช้ค่าจากเอกสาร "หลัก" ภายในคําค้นหาย่อย คุณต้องกำหนดค่าดังกล่าวเป็นตัวแปรก่อนโดยใช้ขั้นตอน let(...)
Node.js
// Fetch reviewers alongside their negative reviews.
const pipeline = db.pipeline()
.collection("/reviewers")
// `let(...)` referred to as `define(...)` in the Web SDK.
.define(field("__name__").as("reviewer_name"))
.select("__name__", array(db.pipeline().collectionGroup("reviews")
.where(field("author").equals(variable("reviewer_name")))
.where(field("rating").lessThan(2))
.select("review", "rating")).as("negative_reviews"))
.execute();
ตัวแปรที่ซ้อนทับกัน
การกำหนดตัวแปรที่มีชื่อที่กำหนดไว้แล้วในขั้นตอน let(...) ก่อนหน้าจะเขียนทับตัวแปรก่อนหน้า คุณสามารถใช้การดำเนินการนี้เพื่ออัปเดตสถานะชั่วคราวเมื่อไปป์ไลน์ดำเนินไป
ตัวแปรที่อ้างอิงในไปป์ไลน์ย่อยเป็นไปตาม กฎการกำหนดขอบเขตแบบเล็กซิคัล ตามที่พบในภาษาโปรแกรมหลายภาษา และหมายถึงตัวแปรที่มีชื่อเดียวกันซึ่งกำหนดโดยไปป์ไลน์ที่ใกล้ที่สุด (หลัก)
การเปรียบเทียบกับ add_fields(...)
ขั้นตอน let(...) ทำงานคล้ายกับขั้นตอน
add_fields(...) แต่แทนที่จะเพิ่ม
ฟิลด์ลงในเอกสาร ขั้นตอนนี้จะกำหนดค่าให้กับตัวแปร