Understanding ndb key class vs KeyProperty
Asked Answered
N

2

6

I've looked through the documentation, the docs and SO questions and answers and am still struggling with understanding a small piece of this. Which should you choose and when?

This is what I've read so far (just sample):

The key class seems pretty straightforward to me. When you create an ndb entity the datastore automatically creates for you a key usually in the form of key(Kind, id) where the id is created for you .

So say you have these two models:

class Blah(ndb.Model):
     last_name = ndb.StringProperty()

class Blah2(ndb.Model):
     first_name = ndb.StringProperty()
     blahkey = ndb.KeyProperty()

So just using the key kind and you want to make Blah1 a parent (or have several family members with the same last name)

lname = Blah(last_name = "Bonaparte")
l_key = lname.put() **OR**
l_key = lname.key.id() # spits out some long id 

fname_key = l_key **OR**
fname_key = ndb.Key('Blah', lname.last_name) # which is more readable.. 

then:

lname = Blah2( parent=fname_key, first_name = "Napoleon")
lname.put()

lname2 = Blah2( parent=fname_key, first_name = "Lucien")
lname2.put()

So far so good (I think). Now about the KeyProperty for Blah2. Assume Blah1 is still the same.

lname3 = Blah2( first_name = "Louis", blahkey = fname_key)
lname3.put()

Is this correct ?

How to query various things

Query Last Name:

Blah.query() # all last names
Blah.query(last_name='Bonaparte') # That specific entity.

First Name:

Blah2.query()
napol =   Blah2.query(first_name = "Napoleon")
bonakey = napol.key.parent().get() # returns Bonaparte's key ??

bona = bonakey.get() # I think this might be redundant

this is where I get lost. How to look for Bonaparte from first name by using either key or keyproperty. I didn't add it here and perhaps should have and that is the discussion of parents, grand parents, great grand parents since Keys keep track of ancestors/parents.

How and why would you use KeyProperty vs the inherent key class. Also imagine you had 3 sensors s1, s2, s3. Each sensor had thousands of readings but you want to keep readings associated with s1 so that you could graph say All readings for today for s1. Which would you use? KeyProperty or the key class ? I apologize if this has been answered elsewhere but I didn't see a clear example/guide about choosing which and why/how.

Narra answered 15/4, 2013 at 16:55 Comment(0)
H
3

I think the confusion comes from using a Key. A Key is not associated with any properties inside of an entity, it is only a unique identifier to locate a single entity. It can be either a number or a string.

Fortunately, all your code looks good except for this one line:

fname_key = ndb.Key('Blah', lname.last_name) # which is more readable.. 

Constructing a Key takes a unique ID, which is not the same as a property. That is, it won't associate the variable lname.last_name with the property last_name. Instead, you can create your record like this:

lname = Blah(id = "Bonaparte")
lname.put()
lname_key = ndb.Key('Blah', "Bonaparte")

You are guaranteed to have only one Blah entity with that ID. In fact, if you use a string like last_name as the ID, you don't need to store it as a separate property. Think of the entity ID as an extra string property that is unique.

Next, Be careful not to assume that Blah.last_name and Blah2.first_name are unique in your queries:

lname = Blah2( parent=fname_key, first_name = "Napoleon")
lname.put()

If you do this more than once, there will be multiple entities with a first_name of Napoleon (all with the same parent key).

Continuing with your code from above:

napol =   Blah2.query(first_name = "Napoleon")
bonakey = napol.key.parent().get() # returns Bonaparte's key ??
bona = bonakey.get() # I think this might be redundant

napol holds a Query, not a result. You need to call napol.fetch() to get all entities with "Napolean" (or napol.get() if you're sure there is just one entity). bonakey is the opposite, it holds the parent entity because of the get() and not Bonaparte's key. If you left the .get() off, then bona would correctly have the parent.

Finally, your question about sensors. You may not need KeyProperty or "inherent" keys. If you have a Readings class like this:

class Readings(ndb.Model):
    sensor = ndb.StringProperty()
    reading = ndb.IntegerProperty()

then you can store them all in a single table without keys. (You may want to include a timestamp or other attribute.) Later, you can retrieve then with this query:

s1_readings = Readings.query(Readings.sensor == 'S1').fetch()
Husking answered 31/5, 2013 at 1:7 Comment(0)
A
1

I'm new to NDB also, and I'm still not understanding all for now, but I think that when you create Blah2 with a parent for Napoleon, you will need the parent to query it or will not appear. For example:

napol = Blah2.query(first_name = "Napoleon")

will not get anything (and you are not using the right format for NDB), but using the parent will do:

napol = Blah2.query(ancestor=fname_key).filter(Blah2.first_name == "Napoleon").get

Don't know if this puts some light for your question.

Arraignment answered 30/5, 2013 at 10:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.