שאילתות בפרויקט

רוב השאילתות ב-Datastore מחזירות ישויות שלמות כתוצאה, אבל לעיתים קרובות אפליקציה מתעניינת רק בכמה מהמאפיינים של הישות. שאילתות של הקרנה מאפשרות לשלוח שאילתה ל-Datastore רק לגבי מאפיינים ספציפיים של ישות שאתם צריכים בפועל, עם חביון ועלות נמוכים יותר מאשר אחזור של הישות כולה.

שאילתות תחזית דומות לשאילתות SQL מהצורה:

SELECT name, email, phone FROM CUSTOMER

אתם יכולים להשתמש בכל תכונות הסינון והמיון שזמינות לשאילתות רגילות של ישויות, בכפוף למגבלות שמפורטות בהמשך. השאילתה מחזירה תוצאות מקוצרות שכוללות רק את המאפיינים שצוינו (name,‏ email ו-phone בדוגמה) עם ערכים. בכל שאר המאפיינים לא מופיעים נתונים.

שימוש בשאילתות תחזיות

דוגמה:

class Article(ndb.Model):
    title = ndb.StringProperty()
    author = ndb.StringProperty()
    tags = ndb.StringProperty(repeated=True)

כך מציינים הקרנה:

def print_author_tags():
    query = Article.query()
    articles = query.fetch(20, projection=[Article.author, Article.tags])
    for article in articles:
        print(article.author)
        print(article.tags)
        # article.title will raise a ndb.UnprojectedPropertyError

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

for article in articles:
        print(article.author)
        print(article.tags)
        # article.title will raise a ndb.UnprojectedPropertyError

אפשר להקרין נכסי משנה שעברו אינדוקס מנכס מובנה. כדי לקבל רק את הנכס city של הנכס המובנה address של איש קשר, אפשר להשתמש בהקרנה כזו:

class Address(ndb.Model):
    type = ndb.StringProperty()  # E.g., 'home', 'work'
    street = ndb.StringProperty()
    city = ndb.StringProperty()
...
class Contact(ndb.Model):
    name = ndb.StringProperty()
    addresses = ndb.StructuredProperty(Address, repeated=True)
...
Contact.query().fetch(projection=["name", "addresses.city"])
Contact.query().fetch(projection=[Contact.name, Contact.addresses.city])

קיבוץ(בשלב ניסוי)

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

Article.query(projection=[Article.author], group_by=[Article.author])
Article.query(projection=[Article.author], distinct=True)

שתי השאילתות שקולות ויפיקו את השם של כל מחבר רק פעם אחת.

מגבלות על תחזיות

שאילתות של תחזיות כפופות למגבלות הבאות:

  • אפשר להקרין רק נכסים שנוספו לאינדקס.

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

  • אי אפשר להקרין את אותו נכס יותר מפעם אחת.

  • אי אפשר להקרין מאפיינים שמופנים אליהם במסנן שוויון (=) או במסנן חברות (IN) .

    לדוגמה,

    SELECT A FROM kind WHERE B = 1
    

    תקין (המאפיין המוקרן לא נמצא בשימוש במסנן השוויון), כמו גם

    SELECT A FROM kind WHERE A > 1
    

    (לא מסנן שוויון), אבל

    SELECT A FROM kind WHERE A = 1
    

    (נכס משוער שמשמש במסנן שוויון) לא.

  • לא ניתן לשמור בחזרה ב-Datastore את התוצאות שמוחזרות על ידי שאילתת הקרנה .

    מכיוון שהשאילתה מחזירה תוצאות שמאוכלסות רק באופן חלקי, אי אפשר לכתוב אותן בחזרה ל-Datastore.

הקרנות ומאפיינים עם כמה ערכים

אם תבצעו הקרנה של מאפיין עם כמה ערכים, לא כל הערכים של המאפיין יאוכלסו. במקום זאת, המערכת תחזיר ישות נפרדת לכל שילוב ייחודי של ערכים חזויים שתואמים לשאילתה. לדוגמה, נניח שיש לכם ישות מסוג Foo עם שני מאפיינים מרובי-ערכים, A ו-B:

entity = Foo(A=[1, 1, 2, 3], B=['x', 'y', 'x'])

ואז שאילתת ההקרנה

SELECT A, B FROM Foo WHERE A < 3

תחזיר ארבע ישויות עם השילובים הבאים של ערכים:

A = 1, B = 'x'
A = 1, B = 'y'
A = 2, B = 'x'
A = 2, B = 'y'

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

מדדים לתחזיות

כדי להריץ שאילתות של הקרנה, צריך לכלול באינדקס של Datastore את כל המאפיינים שצוינו בהקרנה. שרת הפיתוח של App Engine יוצר באופן אוטומטי את האינדקסים הנדרשים בקובץ הגדרת האינדקס,index.yaml, שמועלה עם האפליקציה.

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

SELECT A, B FROM Kind
SELECT A, B, C FROM Kind

אבל אם אתם תמיד מקרינים את המאפיינים A, B ו-C, גם כשC לא נדרש, תצטרכו רק אינדקס אחד.

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

SELECT * FROM Kind WHERE A > 1 ORDER BY A, B

שדורש את האינדקס

Index(Kind, A, B)

המרת השאילתה הזו לאחת משתי שאילתות ההקרנה

SELECT C FROM Kind WHERE A > 1 ORDER BY A, B
SELECT A, B, C FROM Kind WHERE A > 1 ORDER BY A, B

כוללת מאפיין חדש (C), ולכן נדרש ליצור אינדקס חדש Index(Kind, A, B, C). שימו לב ששאילתת התחזית

SELECT A, B FROM Kind WHERE A > 1 ORDER BY A, B

לא ישנה את האינדקס הנדרש, כי המאפיינים המוקרנים A ו-B כבר נכללו בשאילתה הקיימת.