Yep. That's usually the technique I use if I don't embed child objects. -- Ikai Lan Developer Programs Engineer, Google App Engine plus.ikailan.com | twitter.com/ikai
On Tue, Aug 2, 2011 at 9:48 AM, J.Ganesan <[email protected]>wrote: > Is this alternative fine ? > > Entity associationEntity = new Entity("Association"); > associationEntity.setUnindexedProperty( "key1List" , > Arrays.asList( Key[] { k1,k1,k2,k3,k3 } ) ) ; > associationEntity.setUnindexedProperty( "key2List" , > Arrays.asList( Key[] { k8,k6,k4,k1,k7 } ) ) ; > // the developer has to ensure that the cardinality of key1List equals > that of key2List. > > I feel this parallels rdbms representation of many-to-many > relationship. > > J.Ganesan > www.DataStoreGwt.com > > > On Jul 22, 8:21 pm, "Ikai Lan (Google)" <[email protected]> wrote: > > A few comments: > > > > 1. That's more of a 1:1 relationship > > 2. Try to avoid using the term "child". The reason is that when you start > > working with entity groups, you will confuse yourself with terminology. > If > > you don't understand entity groups yet, take a look at these docs: > > > > http://code.google.com/appengine/docs/python/datastore/entities.html#... > > > > Basically, entity groups represent a hierarchical set of related models. > You > > should learn about them because they are the unit of atomicity in high > > replication datastore (the default). > > > > 3. To represent a many-to-many relationship, you would probably want to > have > > a List property on each entity. A List can contain several keys. The > thing > > to be aware of here is that for bidirectional many-to-many relationships, > > you have to manually make sure the key of the related object is in the > > *other* object's list. Example: > > > > Entity ikai = new Entity("User", "ikai"); > > ikai.setProperty("friends", Arrays.asList(String[] { "proppy", "wesley", > > "nick"}); > > > > Entity proppy = new Entity("User", "proppy"); > > proppy.setProperty("friends", Arrays.asList(new String[] { "ikai", > > "nick" })); > > > > If proppy (Johan) and I ever have a falling out, you have to remember to > > remove "johan" from Ikai's list of friends and vice versa. Normalization > > zealots are shaking their heads right now because is possible for > many:many > > relationships like this to get out of sync. > > > > ---- > > Some insights into working with non-relational persistence: > > > > This isn't the only way to represent child objects. You want to optimize > for > > reads when possible because *most* applications are read heavy. A rule of > > thumb is that the number of reads for a given entity are an order of > > magnitude greater than the number of writes. With that in mind, let's > talk > > about an example of a real world data model I've had to recently write. > > > > My problem: I needed to represent users and teams. A user has a role on a > > team. Example: > > > > Ikai - on App Engine team, roles: advocate, support, developer > > proppy - on App Engine team, roles: advocate, support, on Apps team > roles: > > developer, tech writer > > > > In an RDBMS, I'd likely represent this with join tables with an > additional > > field for the "role". This would likely involve several join tables. > > > > I examined my requirements, and I came to the conclusion that I'd need > two > > views: > > > > - What roles does a person have? (What teams and roles does Ikai have?) > > - Given a team, what other roles do people on that team have? (Give the > App > > Engine team, what other teams do people on this team have?) > > > > How did I model this? > > > > Two entity kinds: User entity and Team entity. > > > > On the User entity, I stored a JSON serialized property that looks > roughly > > like this: > > > > { "teams" : { > > "App Engine" : [ "advocate", "support", "developer" ], > > > > } > > > > When I write a User entity, I also write a Team entity. The Team has a > JSON > > serialized property that stores all the roles, team members, and a > snippet > > of information about Team members. > > > > There are tradeoffs in this design, but it suits my purposes: > > > > - It is possible things get out of sync. Since I don't put everything in > the > > same entity group, I can't do a transaction on a Team and User entity > when I > > make a change and need to write two entities. I accepted this, but there > are > > various ways I can mitigate the damage: one way is to use a task queue > task > > that retries until it executes correctly. Since the action to join or > leave > > a team can be idempotent, this is something I can run over and over. > > > > - When I read a User entity, I can do this with a single key, so I don't > > need to do a query and read related objects. This makes my reads very > fast. > > The same is true of Team entities. Now, granted, this might be a bit of > an > > overoptimization, since the number of teams, roles and users might be, > worst > > case scenario, in the tens of thousands and I can probably just read the > > entire datastore and do operations in-memory. > > > > It's possible I'll run into problems later with the way I've designed > this, > > but rather than try to get everything perfect, I opted with a "good > enough" > > design without obvious vlaws to get the project off the ground. Technical > > debt sucks, but sometimes I see developers too much time overthinking > > problems trying to get this perfect. I'm a cynic, but I've accepted that > > I'll always look back on software projects and go, "Man, I designed that > > poorly" anyway, so I might as well mess them up quickly, have a working > > product, figure out where I've messed up, and fix the problems. > > > > Ikai Lan > > Developer Programs Engineer, Google App Engine > > Blog:http://googleappengine.blogspot.com > > Twitter:http://twitter.com/app_engine > > Reddit:http://www.reddit.com/r/appengine > > > > On Thu, Jul 21, 2011 at 3:51 PM, Alexander Herrera < > > > > > > > > > > > > > > > > [email protected]> wrote: > > > Am wondering how in the low level api can i represent a man to many > > > relationship , this is a good approximation? > > > > > Entity entityA = new Entity("TypeA"); > > > entityA.setProperty("name", "nameUserA"); > > > > > Entity entityB = new Entity("TypeA"); > > > entityA.setProperty("name", "nameUserB"); > > > > > ds.put(entityA); > > > ds.put(entityB); > > > > > Entity entityChild = new Entity("entityChild",entityAKey); > > > entityChild.setProperty("name","child"); > > > > > ds.put(entityChild); > > > > > Entity entityChild = new Entity("entityChild",entityBKey); > > > entityChild.setProperty("name","child"); > > > > > ds.put(entityChild); > > > > > -- > > > You received this message because you are subscribed to the Google > Groups > > > "Google App Engine for Java" group. > > > To view this discussion on the web visit > > >https://groups.google.com/d/msg/google-appengine-java/-/PWTINDhJTh0J. > > > To post to this group, send email to > > > [email protected]. > > > To unsubscribe from this group, send email to > > > [email protected]. > > > For more options, visit this group at > > >http://groups.google.com/group/google-appengine-java?hl=en. > > -- > You received this message because you are subscribed to the Google Groups > "Google App Engine for Java" group. > To post to this group, send email to > [email protected]. > To unsubscribe from this group, send email to > [email protected]. > For more options, visit this group at > http://groups.google.com/group/google-appengine-java?hl=en. > > -- You received this message because you are subscribed to the Google Groups "Google App Engine for Java" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/google-appengine-java?hl=en.
