I'm trying to better understand the implications of the deep hierarchy described in the GAE NDB docs
"For example, a revision of a message that "belongs to" an owner, might have a key that looks like"
rev_key = ndb.Key('Account', 'Sandy', 'Message', 'greeting', 'Revision', '2')
I interpret this to mean that if I do Revision(parent=rev_key).put()
then I will have an entity group at the Revision=2 level meaning ancestor queries where ancestor=rev_key
will have strong consistency and writes where parent=rev_key
will be limited to 1/sec.
But what are the implications further up the hierarchy?
For instance, say I have
rev_key_B = ndb.Key('Account', 'Sandy', 'Message', 'greeting', 'Revision', '3')
Is write speed limited to 1/sec at the rev_key_B
level or, since they share a parent's parent, i.e. ndb.Key('Account', 'Sandy', 'Message', 'greeting')
, is write speed limited even higher up the ancestor path and, ultimately, to the entire entity group all the way up to ndb.Key('Account', 'Sandy')
?
Same questions re: strong consistency. Would Revision.query(ancestor=ndb.Key('Account', 'Sandy', 'Message', 'greeting'))
have strong consistency?
Let's see
Means that every entity has strong consistency following the entity path. So you are correct.
Lets see it in action: Create the entities
That will give you strong consistency and grant you the ability to query all the above entities inside transactions as well.
I am using the
get_or_insert
which does what it says inside a transaction efficiently creating an entity if it does not exist with the key provided. This requires the key or id to be unique. So this way you cannot have 2 messages withGreeting
andSandy as parent
.The way keys work is like a binary tree.
S = Sandy, M=Message, R=Revision
Each path to the end or shorter can be run in transaction and provide strong consistency*.
Reply in comment:
As this example is not sufficient to show the efficiency of GAE and NDB maybe the below will.
Imagine that you have a jukebox with queues per room let's say. And people are queueing songs to each queue of each jukebox.
J=Jukebox, Q=queue, S=Song
In this example it is convenient to use paths, so each operation by a user, knowing wich jukebox, queue can CUD the song entity with consistency to jukebox, queue and song.
*Btw you can also lock paths not starting from root
Also keep in mind that Queries inside transactions must include ancestor filters