投影查詢

大多數 Datastore 查詢結果會傳回完整實體,但應用程式真正需要的往往只有該實體的幾項屬性。您可以按照實際需求,運用「投影查詢」在 Datastore 中單純查詢某個實體的特定屬性,相較於擷取完整實體,這種方式更有助於減少延遲時間及降低費用。

投影查詢近似於下列形式的 SQL 查詢:

SELECT name, email, phone FROM CUSTOMER

您可以使用所有適用於查詢標準實體的篩選及排序功能,但必須遵守以下說明的幾項限制。查詢會傳回只包含指定屬性的簡略版結果 (以此範例來說就是 nameemailphone),且這些屬性均已填入值;其他所有屬性均沒有資料。

在 Go 1.11 中使用投影查詢

準備 Query 時,請使用 Project 方法指定投影方式:

q := datastore.NewQuery("People").Project("FirstName", "LastName")

處理這些查詢結果的方式與處理標準實體查詢結果的方式相同。舉例來說,您可以疊代處理結果。

以下範例會查詢所有 EventLog 項目的 TitleReadPathDateWritten 屬性,並依 DateWritten 的遞增順序排序,然後將每個屬性的值寫入應用程式記錄:

q := datastore.NewQuery("EventLog").
	Project("Title", "ReadPath", "DateWritten").
	Order("DateWritten")
t := q.Run(ctx)
for {
	var l EventLog
	_, err := t.Next(&l)
	if err == datastore.Done {
		break
	}
	if err != nil {
		log.Errorf(ctx, "Running query: %v", err)
		break
	}
	log.Infof(ctx, "Log record: %v, %v, %v", l.Title, l.ReadPath, l.DateWritten)
}

分組(實驗版)

投影查詢可以使用 Distinct 方法,確認結果集只傳回完全不重複的結果。如有多個實體的投影屬性包含相同的值,這種方式只會傳回第一個結果。

q := datastore.NewQuery("Person").
	Project("LastName", "Height").Distinct().
	Filter("Height >", 20).
	Order("-Height").Order("LastName")

投影限制

投影查詢必須遵循以下限制:

  • 只能投影已建立索引的屬性。

    未編入索引的屬性不支援投影功能 (不分明確或隱含)。長度超過 1500 個位元組的字串,以及包含超過 1500 個元素的位元組陣列,均不編入索引。

  • 不能重複投影同一個屬性。

  • 不能投影等式 (=) 篩選器參照的屬性。

    例如,假設使用者要求系統 將文字從英文翻譯成法文

    SELECT A FROM kind WHERE B = 1
    

    有效 (等式篩選器未使用投影屬性),

    SELECT A FROM kind WHERE A > 1
    

    (非等式篩選器) 也有效,但

    SELECT A FROM kind WHERE A = 1
    

    (等式篩選條件使用了投影屬性) 則無效。

  • 不應將投影查詢傳回的結果存回 Datastore。

    由於這類查詢只傳回部分填入的結果,因此不應再將結果寫回 Datastore。

投影與多值屬性

投影有多個值的屬性時,並不會填入該屬性的所有值,而是每找到一組與查詢相符且不重複的投影值,就傳回一個獨立實體。例如,假設有一個 Foo 種類的實體,包含兩個多值屬性 AB

entity := Foo{A: []int{1, 1, 2, 3}, B: []string{"x", "y", "x"}}

之後,投影查詢

q := datastore.NewQuery("Foo").Project("A", "B").Filter("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

不過,如果一律投影 ABC 等屬性 (即使是在不需要 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

「不會」變更需要的索引,因為現有查詢中已包含投影屬性 AB