Take a look at Building Scalable, Complex Apps on App Engine (pdf), a fascinating talk given at Google I/O by Brett Slatkin. He addresses the problem of building a scalable messaging service like Twitter.
Here's his solution using a list property:
class Message(db.Model):
sender = db.StringProperty()
body = db.TextProperty()
class MessageIndex(db.Model):
#parent = a message
receivers = db.StringListProperty()
indexes = MessageIndex.all(keys_only = True).filter('receivers = ', user_id)
keys = [k.parent() for k in indexes)
messages = db.get(keys)
This key only query finds the message indices with a receiver equal to the one you specified without deserializing and serializing the list of receivers. Then you use these indices to only grab the messages that you want.
Here's the wrong way to do it:
class Message(db.Model):
sender = db.StringProperty()
receivers = db.StringListProperty()
body = db.TextProperty()
messages = Message.all().filter('receivers =', user_id)
This is inefficient because queries have to unpackage all of the results returned by your query. So if you returned 100 messages with 1,000 users in each receivers list you'd have to deserialize 100,000 (100 x 1000) list property values. Way too expensive in datastore latency and cpu.
I was pretty confused by all of this at first, so I wrote up a short tutorial about using the list property. Enjoy :)