Consider a social bookmarking application like del.icio.us . del.icio.us stores each user's bookmarks in a shared, on-line environment. A non-relational database might store all bookmarks in a flat file:
Such a scheme is wasteful of space, as a user's information is duplicated with every bookmark record. It's also inefficient to query. A relational design would instead define the following two tables: Account Table
Bookmark Table
Note that each table has a column named key. This is a system-generated unique id that is provided for every table you create. Each bookmark record now only stores a key reference into the Account table, not an entire user's account information. If the submitter_key field is 1, the submitter was Monta Ellis. If it is 2, the submitter was Stephen Jackson. We then use an account key to get all the bookmarks of a particular user. For instance, all Monta's bookmarks could be retrieved with: "Select * from Bookmark where submitter_key=1" Of course the "1" would probably be a variable in a real query.When keys are used to relate the tables of data, we call the database a "relational database". Relational Database with Google's AppengineWith App Engine, classes are used to define tables and a special class called ReferenceProperty is used to define relations.
Instead of recording an email for each user, we record their entire Google user account. The submitter is defined as a ReferenceProperty. Beneath the hood, a key representing a record in the Account table is stored, but the App Engine programmer can treat the submitter as an Account object. Now consider the query to find all the bookmarks of a particular user. Above, we described the following query: "Select * from Bookmark where submitter_key=1" And such a query would be used in some systems and could be used in App Engine. However, with App Engine's higher-level API, you need not explicitly refer to a key. Instead, a query such as the following can be used: user = users.get_current_user() accountQuery = db.GqlQuery("Select * from Account where user=:1",user) account = accountQuery.get() # get the one and only result bookmarks = db.GqlQuery("Select * from Bookmark where submitter=:1",account) Even though the submitter field in the class Bookmark is a ReferenceProperty, the system knows that that reference is to an Account, so it allows for the comparison. You can also set the submitter field directly to an account. For instance, when a bookmark is entered, the controller might do the following: user = users.get_current_user() accountQuery = db.GqlQuery("Select * from Account where user=:1",user) account = accountQuery.get() # get the one and only result bookmark=Bookmark() bookmark.url=self.request.get('url') bookmark.note=self.request.get('note') bookmark.submitter=account bookmark.put() Extending the Example: Tags on Bookmarks Del.icio.us allows users to specify tags on each bookmark. For instance, Monta might tag montaellis.com as "basketball" and "personal". How would you modify the database to allow for tags? |