Überlegungen zum Google App Engine DataStore API

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Die Google App Engine hat ein spezielles Persistenzmodell und unterstützt keine relationale Datenbank. Dies erfordert ein Umdenken. Statt Datensätze in Tabellen zu normalisieren und zu kombinieren, können beliebige Objekte gespeichert oder geladen werden.

Ich hatte neulich mal über ein Datenmodell für ein Forum nachgedacht. Wie sähe das für den Google Datastore aus?

Sagen wir, ich will die übliche Startseite eines Forums anzeigen. Dies ist eine Tabelle mit den sortierten Forennamen, der Anzahl der Themen und Beträge pro Forum und der Angabe, wann wer das letzte mal etwas geschrieben in diesem Forum geschrieben hat. Pro Forum werden dann die zuletzt diskutierten Themen mit der Anzahl der Antworten und wieder des letzten Autors angezeigt.

Die Foren könnte ich mir so holen:

Code: Alles auswählen

for forum in Forum.all().order('index'):
	...
Da ich nicht effizient zählen kann, muss ich pro Forum die Anzahlen explizit verwalten:

Code: Alles auswählen

class Forum(db.Model):
	title = db.StringProperty(required=True)
	description = db.TextProperty(required=True)
	index = db.IntegerProperty(required=True)
	topic_count = db.IntegerProperty(required=True)
	post_count = db.IntegerProperty(required=True)
	
	def create_topic(self, title):
		def doit():
			topic = Topic(title=title, forum=self)
			topic.put()
			self.topic_count += 1
			self.put()
		db.run_in_transaction(doit)
		
class Topic(db.Model):
	title = db.StringProperty(required=True)
	forum = db.ReferenceProperty(Forum, collection_name='topics')
	reply_count = db.IntegerProperty(required=True)
	
	def destroy(self):
		def doit():
			self.forum.topic_count -= 1
			self.forum.put()
			self.delete()
		db.run_in_transaction(doit)
Ich bin unsicher, ob das "+=" und "-=" so funktioniert, da Transaktionsfunktionen seiteneffektfrei sein sollen. Das ist bei mir offensichtlich nicht der Fall. Doch wie sonst?

Ich möchte jetzt den jeweils letzten Autor speichern:

Code: Alles auswählen

class Forum...
	last_author = db.ReferenceProperty(User)

class Topic...
	last_author = db.ReferenceProperty(User)
	
	def create_post(self, author, text):
		def doit():
			post = Post(author=author, text=text, topic=self)
			post.put()
			self.reply_count += 1
			self.last_author = author
			self.put()
			self.forum.post_count += 1
			self.forum.last_author = author
			self.forum.put()
		db.run_in_transaction(doit)
Ich befürchte jedoch, ich habe damit immer noch ein N+1-Anfragenproblem, da jetzt beim Auflisten der Foren für jedes Forum noch das passende Author-Objekt geladen werden muss. Angenommen, ein Author hätte einen Namen und eine URL, müsste ich beide Eigenschaften explizit speichern. Das missfällt mir. Wenn ich z.B. die Berechnung der URL ändern wollen würde, müsste die Änderung in der ganzen Datenbank nachgetragen werden.

Würde man einen Beitrag wieder löschen, müsste übrigens auf nicht-triviale Weise der dann letzte Autor nachgetragen werden.

Irgendwie würde ich mich dem Ansatz von couchDB wohler fühlen, wo man strukturierte JSON-Dokumente ablegen und auf dem Server auch mit Hilfe von JavaScript-Funktionen filtern und modifizieren kann.

Stefan
Antworten