Sumeet Pareek
Sumeet Pareek

Reputation: 2829

How to get to the key name of a referenced entity property from an entity instance without a datastore read in google app engine?

Consider I have the following models -

class Team(db.Model): # say I have just 5 teams
  name = db.StringProperty()

class Player(db.Model): # say I have thousands of players
  name = db.StringProperty()
  team = db.ReferenceProperty(Team, collection_name="player_set")
  1. Key name for each Team entity = 'team_' , and for each Player entity = 'player_'

  2. By some prior arrangement I have a Team entity's (key_name, name) mapping available to me. For example (team_01, United States Of America), (team_02, Russia) etc

  3. I have to show all the players and their teams on a page. One way of doing this would be -

    players = Player.all().fetch(1000) # This is 1 DB read
    for player in players: # This will iterate 1000 times
      self.response.out.write(player.name) # This is obviously not a DB read
      self.response.out.write(player.team.name) #This is a total of 1x1000 = 1000 DB reads
    
  4. That is a 1001 DB reads for a silly thing.

  5. The interesting part is that when I do a db.to_dict() on players, it shows that for every player in that list there is 'name' of the player and there is the 'key_name' of the team available too.

  6. So how can I do the below ??

    players = Player.all().fetch(1000) # This is 1 DB read
    for player in players: # This will iterate 1000 times
      self.response.out.write(player.name) # This is obviously not a DB read
      self.response.out.write(team_list[player.<SOME WAY OF GETTING TEAM KEY NAME>]) # Here 'team_list' already has (key_name, name) for all 5 teams
    

I have been struggling with this for a long time. Have read every available documentation.

I could just hug the person that can help me here :-)

Disclaimer: The above problem description is not a real scenario. It is a simplified arrangement that represents my problem exactly. I have run into it in a rater complex and big GAE appication.

Upvotes: 1

Views: 191

Answers (4)

Greg
Greg

Reputation: 10360

inside your loop, Player.team.get_value_for_datastore(player) will return the team's Key object without fetching anything from datastore.

If you wanted to pre-fetch all of the teams for a set of players (pretend you had more than 5, so didn't want to fetch them all if you're not going to need them all), then this blog post explains a good technique.

Upvotes: 3

Dave W. Smith
Dave W. Smith

Reputation: 24966

If you have a Team that a lot of Players refer to by key, and you want to list some subset of Player properties when you display the Team, and you want to minimize database reads, then you're going to probably need to denormalize, and cache some subset of Player information in a serialized blob (or a chunk of Json) attached to the Team. Lazily recompute the blob on membership change (if membership changes less frequently than team views, this is a definite win). This kind of update is the perfect use case for a background task.

Upvotes: 1

Peter Knego
Peter Knego

Reputation: 80340

Starting from your given situation the only way to lower DB cost is to cache Team. If you use the new NDB API this is already done for you under the hood.

Upvotes: 1

Adam Crossland
Adam Crossland

Reputation: 14213

A ReferenceProperty stores a Key. You should be able to use the Key's id_or_name method to get the key_name.

Upvotes: 0

Related Questions