Tagging with Appengine DataStore

I've been looking into how to implement a tagging mechanism with Appengine (Python). By using a StringListProperty, you can associate a list of tags with an entity. The model would look something like this:


from google.appengine.ext import db

class Sample(db.Model):
name = db.StringProperty(required=True)
tags = db.StringListProperty()


Now, assuming we want to find the entities tagged with a given word, we can use a query like this:


q = db.GqlQuery("SELECT * FROM Sample where tags = :1",'z')


If we want to find all entities that have ANY of these tags (OR) we can query with GqlQuery or filter:


q = db.GqlQuery("SELECT * FROM Sample where tags in :1",['a','z'])

q = domain.Sample.all()
q.filter("tags in ", ['b','d'])


When we want to find entities with ALL of the given tags:


q = db.GqlQuery("SELECT * FROM Sample where tags = :1 and tags = :2",'b','c')
q = domain.Sample.all()
q.filter("tags = ", 'b')
q.filter("tags = ", 'c')



Too easy!

If you have an appengine project, you can try this code out by adding the entity (Sample - listed above) to your domain model and run the following in your development console (http://localhost:8080/_ah/admin/interactive):


import domain

domain.Sample(name='t1',tags=['a','b','c']).put()
domain.Sample(name='t2',tags=['b','c','d']).put()
domain.Sample(name='t3',tags=['c','d','e']).put()
domain.Sample(name='t3',tags=['x','Y','z']).put()

def display(r):
for r in results:
print r.name +" tags = "+' '.join(r.tags)


print "FIND WITH THIS TAG"
q = db.GqlQuery("SELECT * FROM Sample where tags = :1",'z')
results = q.fetch(5)
display(results)

print "FIND WITH ANY OF THESE TAGS (OR)"
q = db.GqlQuery("SELECT * FROM Sample where tags in :1",['a','z'])
results = q.fetch(5)
display(results)

print "FIND WITH ANY OF THESE TAGS (OR)"
q = domain.Sample.all()
q.filter("tags in ", ['a','z'])
results = q.fetch(5)
display(results)

print "FIND WITH ANY OF THESE TAGS (AND)"
q = db.GqlQuery("SELECT * FROM Sample where tags = :1 and tags = :2",'b','c')
results = q.fetch(5)
display(results)

print "FIND WITH ALL OF THESE TAGS (AND)"
q = domain.Sample.all()
q.filter("tags = ", 'b')
q.filter("tags = ", 'c')

results = q.fetch(5)
display(results)


This should produce the following result:


FIND WITH THIS TAG
t3 tags = x Y z
FIND WITH ANY OF THESE TAGS (OR)
t1 tags = a b c
t3 tags = x Y z
FIND WITH ANY OF THESE TAGS (OR)
t1 tags = a b c
t3 tags = x Y z
FIND WITH ANY OF THESE TAGS (AND)
t1 tags = a b c
t2 tags = b c d
FIND WITH ALL OF THESE TAGS (AND)
t1 tags = a b c
t2 tags = b c d


So, it's easier than I thought. But I'm not experienced with DataStore yet, and I don't know if there are inherit limitations with this approach - remember, there are limits on the way you retrieve data.

Popular posts from this blog

Using the Crystal Reports Java API to generate PDF

No Scope registered for scope request

Using Selenium WebDriver to select JSF/PrimeFaces selectOneMenu options