Is it possible to create references in Google App Engine? - database

Let's say I have a datastore that contains mother, father, and child objects. Inside the Mother and Father objects I have a field called child which stores a reference to their child. Is it possible to reference this child from both mother and father without creating duplicate child instances for each (in the style of OOP). Is this how databases work at all?

Yes, you can use the db.ReferenceProperty to do exactly that.
A reference property simply stores the unique key of the entity it references. So the mother and father entities could each contain a copy of the key corresponding to their child like this:
class Child(db.Model):
... # child properties
class Father(db.Model):
child = db.ReferenceProperty(Child)
...
class Mother(db.Model):
child = db.ReferenceProperty(Child)
...

Related

Objectify - get all of a type regardless of parent

I have child entities with #Parent key ref in them.
When I give the parent key, I am able to get the child entity like this:
OfyService.ofy()
.load()
.type(Child.class)
.parent(parentKey)
.id(childId).now();
I tried to access the child entity directly without giving the parent key, but that doesn't work (returns null):
OfyService.ofy()
.load()
.type(Child.class)
.id(childId).now();
Is there another way to query one or all instances of a kind regardless of parent?
For example, _ah/admin is able to list all the entities of a Kind regardless of the parent.
Iterable<Child> children = ofy().load().type(Child.class);

Proper way to organize data models in a MEAN stack application

I am making an MEAN stack app and use Mongoose alongside Mongo. I am struggling with organizing my objects in database. All works as expected but I have a feeling that the way I am doing things is wrong, but can't seem to find any resources on the topic that could help me, thus I hope somebody with some experience can share it with me.
I use Mongoose to create several schemas, and there is one dilemma I am facing, concerning nested objects in MongoDB.
Let's say I have a model that looks like that:
ParentSchema:{
property1:String,
children:[{}]
}
So, property1 is just some string, 'children' is an array that will contain objects of type 'Child' with some other properties, but also another array (f.ex. 'grandchildren:[{]} ), this time with another type of objects (Grandchild).
Child and Grandchild have no schemas and do not exist outside of the Parent, and will most likely be unique to each instance of Parent, so two Parents would not be sharing a Child object.
In my app, I am able to use urls such as '/parent/:id1/Child/:id2/Grandchild/:id3', where 'id1' is an actual id of Parent that Mongo generates, while 'id2' is an index of Child object instance stored in Parents array. The same goes for instances of Grandchildren stored inside Child object.
I was thinking that maybe having separate schemas for all 3 objects, and just saving references to objects is the way to go, like this:
ParentSchema:{
prop1:String,
children:[{type:ObjectId, ref:'Child'}]
}
ChildSchema:{
prop1:String,
granchildren:[{type : ObjectId, ref: 'Grandchild'}]
}
GrandChildSchema:{
prop1:String,
prop2:String
}
..but was unsure, as for me it implies that Child and GrandChild instances would be shared between different parents, however it seems easier to work with.
To sum up, I would like to know is:
which approach should I choose and why: first, second or maybe some other that I do not know about yet.
If I were to choose the second approach, should I create a separate API route for each of the objects?
How would I go about creating then? My wish is for the process to look like so:
Start creating Parent -> start creating first Child -> create some Grandchildren ->
finish creating Child -> start creating second Child -> ... -> finish creating Parent.
I apologize if the question is somehow weird, I will try to clarify as best as I can if required.
I would go with the second approach for a couple of reasons:
Schemas have better readability in my opinion.
They allow for data validation which you lack in the first approach.
Please note the answer below is primarily opinion based.
For the API design:
I think its really up to you as to which paths to expose to the consumer, since you've stated Child and Grandchild do not have the right to exist without a parent - I think your routes are fine as they are.
And finally - your process for creating these entities look fine to me. I would do the same thing myself.

Hierarchical queries for Parent-Child entities in App Engine

Is it possible to query Parent + Child entities in a single query pass?
This would require a JOIN in SQL, but in the underlying BigTable the keys are sequential, so it should theoretically by possible to scan Parent and Child entities in a single pass. For example:
Parent-1
Parent-1-Child-A
Parent-1-Child-B
Parent-1-Child-C
Parent-2
Parent-2-Child-D
Parent-3
Parent-3-Child-E
Ancestor queries limit the scope to a single Parent. What I'm looking for is Query by key range that isn't limited to a single Kind.
Something like that doesn't exist by default.
One way I have addressed this is by having each entity store all of it's possible paths as a repeated property, including itself if you want it to be returned in the query the way ancestor queries do. In addition store the path of the immediate parent.
ie (I will include an example with more than 2 levels)
Parent-1
paths = ['Parent-1']
parent = []
Parent-1-Child-A
paths = ['Parent-1','Parent-1/Child-A']
parent = ['Parent-1']
Parent-1-Child-C
paths = ['Parent-1','Parent-1/Child-C']
parent = ['Parent-1']
Parent-1-Child-C-Child-F
paths = ['Parent-1','Parent-1/Child-C','Parent-1/Child-C/Child-F' ]
parent = ['Parent-1/Child-C']
Parent-1-Child-C-Child-E
paths = ['Parent-1','Parent-1/Child-C','Parent-1/Child-C/Child-E' ]
parent = ['Parent-1/Child-C']
This way you can query for any key range and limit the depth to immediate children) Ancestor queries have no means of limiting depth.
This would require you to use PolyModel (you haven't said if your using python or java - I don't know if java has a PolyModel analog). So Parent and Child would inherit from Node which would be based on PolyModel
class Node(ndb.PolyModel):
pass
class Parent(Node):
pass
class Child(Node):
pass
Though you may not need different classes for parent and child.
One thing to note, if you use ancestors/parents in the key you can not re-arrange your heirarchies without completely copying/re-writing all of the children

Reference property for parent/ancestor relation?

What is the best practice when it comes to reference properties for parent/ancestor relations in AppEngine? Should I add a reference property pointing from the parent to the child to make it easy to access the child in the parent, or should I just "suck it up" and do a ancestor query from the parent to get it's children.
If there is only one child, you could use a known key_name so you can directly fetch the child (since you know the parent's key). This can be useful because any time you know the parent's key name or id you can easily fetch the child directly.
child_key = db.Key.from_path('ChildKind', 'knownname', parent=parent_key)
child = db.get(child_key)
If there are multiple children you could potentially store a list of keys (it can be unindexed) on the parent, or use an ancestor query. I would say it depends how your data is updated, reported on (presented), and the volume of data. In other words it depends on the needs of your application.

What does ancestor mean in the google app engine datastore

Can anyone tell or define more what is "ancestor" and give an example on it and also what it is for? I just can't grasp what it really is.
Reference: http://code.google.com/appengine/docs/python/datastore/queryclass.html#Query_ancestor
Thanks.
Transactions in GAE only exist within ancestor-descendant groups. Equivalently, quoting the docs at the URL I just gave,
All datastore operations in a
transaction must operate on entities
in the same entity group
and an "entity group", per this page in the docs, are defined by:
When the application creates an
entity, it can assign another entity
as the parent of the new entity, using
the parent argument in the Model
constructor. Assigning a parent to a
new entity puts the new entity in the
same entity group as the parent
entity.
"Ancestor" is just the transitive closure of "parent" -- i.e., given an entity, its ancestors are, its parent, its parent's parent, and so forth.

Resources