ייחודי

תיאור

איתור כל השילובים השונים של ערכים בסדרת ביטויים.

לשלב distinct(...) יש תחביר דומה לזה של select(...), כי הוא מקבל ביטוי אחד או יותר שאפשר לבחור. אפשר להשתמש במחרוזות כשהביטוי הוא רק הפניה לשדה:

דוגמאות

Node.js
let cities = await db.pipeline()
  .collection("cities")
  .distinct("country")
  .execute();

cities = await db.pipeline()
  .collection("cities")
  .distinct(
    field("state").toLower().as("normalizedState"),
    field("country"))
  .execute();

Web

let cities = await execute(db.pipeline()
  .collection("cities")
  .distinct("country"));

cities = await execute(db.pipeline()
  .collection("cities")
  .distinct(
    field("state").toLower().as("normalizedState"),
    field("country")));
Swift
let results = try await db.pipeline()
  .collection("books")
  .distinct([
    Field("author").toUpper().as("author"),
    Field("genre")
  ])
  .execute()

Kotlin

var cities = db.pipeline()
    .collection("cities")
    .distinct("country")
    .execute()

cities = db.pipeline()
    .collection("cities")
    .distinct(
        field("state").toLower().alias("normalizedState"),
        field("country")
    )
    .execute()

Java

Task<Pipeline.Snapshot> cities;
cities = db.pipeline()
        .collection("cities")
        .distinct("country")
        .execute();

cities = db.pipeline()
        .collection("cities")
        .distinct(
                field("state").toLower().alias("normalizedState"),
                field("country"))
        .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field

cities = client.pipeline().collection("cities").distinct("country").execute()

cities = (
    client.pipeline()
    .collection("cities")
    .distinct(Field.of("state").to_lower().as_("normalizedState"), "country")
    .execute()
)
Java
Pipeline.Snapshot cities1 =
    firestore.pipeline().collection("cities").distinct("country").execute().get();

Pipeline.Snapshot cities2 =
    firestore
        .pipeline()
        .collection("cities")
        .distinct(toLower(field("state")).as("normalizedState"), field("country"))
        .execute()
        .get();

התנהגות

השלב distinct(...) פועל באופן דומה לשלב aggregate(...) ללא קבוצות. מידע נוסף זמין במאמרים בנושא aggregate(...) וselect(...).

חיפוש ערכים שונים בשדה

לדוגמה, כדי לקבל רשימה של כל המדינות באוסף cities הבא:

Node.js

await db.collection("cities").doc("SF").set({name: "San Francisco", state: "CA", country: "USA"});
await db.collection("cities").doc("LA").set({name: "Los Angeles", state: "CA", country: "USA"});
await db.collection("cities").doc("NY").set({name: "New York", state: "NY", country: "USA"});
await db.collection("cities").doc("TOR").set({name: "Toronto", state: null, country: "Canada"});
await db.collection("cities").doc("MEX").set({name: "Mexico City", state: null, country: "Mexico"});

אפשר למצוא מדינות שונות באמצעות:

Node.js

const cities = await db.pipeline()
  .collection("/cities")
  .distinct("country")
  .execute();

שיוצרת את התוצאה הבאה:

{ country: "USA" }
{ country: "Canada" }
{ country: "Mexico" }

פלט ייחודי של ביטויים

אפשר גם למצוא את השילובים הייחודיים של כמה שדות, או ביטויים מורכבים יותר. לדוגמה:

Node.js

const cities = await db.pipeline()
  .collection("/cities")
  .distinct(
    field("state").toLower().as("normalized_state"),
    field("country"))
  .execute();

כדי לקבל:

{ country: "USA", normalized_state: "ca" }
{ country: "USA", normalized_state: "ny" }
{ country: "Canada", normalized_state: null }
{ country: "Mexico", normalized_state: null }

התנהגויות שקולות

ההתנהגות של השוואה בין ערכים שונים זהה להתנהגות של השוואה בין ערכים זהים.

כלומר, ערכים שווים, למשל ערכים מספריים שווים מבחינה מתמטית, נחשבים לאותו ערך ייחודי, ללא קשר לסוגים המקוריים שלהם (מספרים שלמים של 32 ביט, מספרים שלמים של 64 ביט, מספרים עם נקודה עשרונית, מספרים עשרוניים וכו').

לדוגמה, באוסף numerics עם מסמכים שונים שמכילים ערכים של foo מספר שלם של 32 ביט 1, מספר שלם של 64 ביט 1L ומספר נקודה צפה 1.0, הפונקציה distinct(...) תחזיר רק תוצאה אחת.

במקרים כאלה שבהם קיימים בערכת הנתונים ערכים שונים ששווים זה לזה, ערך הפלט של הקבוצה יכול להיות כל אחד מהערכים האלה. בדוגמה הזו, הערך foo יכול להיות מוחזר כ-1, 1L או 1.0.

גם אם נראה שהבחירה היא דטרמיניסטית, לא כדאי להסתמך על ההתנהגות של בחירת ערך ספציפי.

שימוש בזיכרון

אופן ההפעלה של שלב distinct(...) תלוי באינדקסים הזמינים. אם אופטימיזציית השאילתות לא בוחרת אינדקס מתאים, הפונקציה distinct(...) דורשת אחסון בזיכרון של כל הערכים השונים.

אם יש מספר גדול מאוד של ערכים ייחודיים, או ערכים גדולים מאוד (למשל, ערכים ייחודיים גדולים), יכול להיות שלא יהיה מספיק זיכרון בשלב הזה.

במקרים כאלה, כדאי להחיל מסננים כדי להגביל את מערך הנתונים שעליו מתבצעת הפעולה distinct(...), או ליצור אינדקסים כמומלץ כדי להימנע משימוש רב בזיכרון.

הכלי Query Explain יספק מידע על תוכנית ההפעלה של השאילתה ועל נתוני פרופילים שיעזרו לכם באיתור באגים.