2016-09-20 96 views
1

如果您正在處理記錄的層次結構,其中大多數鍵都具有祖先,那麼在您檢索葉之前是否必須創建所有鍵的鏈?AppEngine數據存儲:分層查詢

例(圍棋):

rootKey = datastore.NewKey(ctx, "EntityType", "", id1, nil) secondGenKey = datastore.NewKey(ctx, "EntityType", "", id2, rootKey) thirdGenKey = datastore.NewKey(ctx, "EntityType", "", id3, rootKey)

你如何通過thirdGenKey描述的記錄,而不必申報鍵的所有它上面的層次結構的級別?

回答

2

爲了獲得一個單獨的實體,其密鑰必須是全局唯一的 - 這是通過每個實體密鑰在其實體組中唯一實施的。出於這個原因,祖先路徑構成了實體關鍵的固有部分。

因此,獲得具有較強一致性的單個實體的唯一方法是指定其祖先路徑。這可以通過密鑰或祖先查詢來完成。

如果你不知道完整的祖先路徑,你唯一的選擇是對實體的屬性查詢,但謹記:

  • 這可能不是你的應用程序中是唯一的
  • 你會受到最終一致性的影響。
+0

這就是我確認。因此,如果您的層次結構由許多祖先級別組成,則需要構建一個帶有ID和無祖先的密鑰,另一個帶有ID的密鑰以及該祖先的第一個密鑰,另一個帶有ID的密鑰以及第二個密鑰這個祖先等等,直到你處於正確的級別才能訪問你的主要記錄,是否正確?換句話說,如果你在N級有一條記錄,那麼你將不得不構建一個N鍵鏈,以便以較強的一致性檢索它,對嗎? –

+0

@DustinOprea,這是正確的。然而,你對強一致性的評論是有誤導性的,但是所有的查找(明確地通過關鍵字獲得)都是非常一致的,它與必須存在的關鍵祖先沒有任何關係。當您執行查詢(返回0-n個實體)而不將查詢綁定到單個祖先(實體組)時,最終的一致性將發揮作用。 –

+0

@DanMcGrath是的..這是祖先的存在,使它成爲SC,但你需要整個鏈下降得足夠遠。謝謝,丹。 –

1

爲了補充tx802的回答是:

如果您想通過鍵載入一個實體,你需要關鍵。如果密鑰是具有父代的密鑰,爲了形成/創建密鑰,還需要先創建父密鑰。父鍵鍵的一部分,就像數字ID或字符串名稱一樣。

從實現角度來看:datastore.Key是一個結構:

type Key struct { 
    kind  string 
    stringID string 
    intID  int64 
    parent *Key 
    appID  string 
    namespace string 
} 

爲了構建一個Key其中有一個家長,你必須構建父鍵也遞歸。如果您發現它太冗長以至於無法始終創建密鑰層次結構,則可以爲其創建輔助函數。

爲了簡單起見,我們假設所有的鍵都使用相同的實體名稱,而我們只使用數字ID。它可能看起來像這樣:

func createKey(ctx context.Context, entity string, ids ...int) (k *datastore.Key) { 
    for _, id := range ids { 
     k = datastore.NewKey(ctx, entity, "", id, k) 
    } 
    return 
} 

有了這個輔助函數,你的榜樣減少到這一點:

k2 := createKey(ctx, "EntityType", id1, id2) 
k3 := createKey(ctx, "EntityType", id1, id3) 
+0

謝謝你的進一步澄清。看起來這個模型並沒有真正適應相同實體類型的同種/遞歸樹。例如,在我的例子中,我有一個很大的分類樹(其中一行中的所有子項的祖先都是父項),但是沒有實際的方法來1)將表示父項的標識符存儲爲記錄中的項,也不是2)從另一個記錄中引用這些分類器中的一個(因爲這些ID只對祖先是唯一的,所以遞歸/嵌套祖先/父鍵也必須作爲屬性存儲)。 (續...) –

+0

...當然,爲了立即保持一致。當然,我可以創建一個全球唯一的密鑰並將其用於查找/引用,但這只是最終一致。看起來這個模型最方便,因爲當你有幾個離散的祖先隨手可用來建立複合關鍵字時(動態數量級別不可行)和/或你只有少數幾個異構嵌套實體類型,例如公司 - >用戶>發票。思考?我很感謝你的見解。我試圖弄清楚這裏的模式。 –

+0

@DustinOprea存儲多種「實用」方式來存儲關鍵信息。一種選擇是擁有「Key」類型的屬性,並且該屬性的值可以是任何「Key」值,包括具有父項的鍵。另一種選擇是將ID列表存儲在屬性中(因爲您只使用ID而不使用字符串名稱);你甚至可以選擇像''id1,id2''那樣將它們存儲在單個字符串中,或​​者作爲一個多值屬性(slice)來存儲,比如'[id1,id2]';並且只有這些ID,你可以重新構建你需要的「Key」,例如,在答案中發佈'createKey()'函數。 – icza