Retrieving All Recently Created Entities

Searching the datastore using date-based entity properties can often be confusing to new App Engine developers. Here’s how to search for all recently created entities.

First, each entity has to record the time it was created. Add the following line of code when constructing your entities (entity represents the Entity object being created):

entity.setProperty("add_date", new Date());//Records the date this entity was added.

Here’s the code for the query. This code example searches for all entities created within the last 24 hours with a kind of mail. The resulting entities are placed into the variable results (which is a standard java.util.List object).

/**
 * Creates a Date object that represents a point in time 
 * 24 hours ago.
 */
Date current_date = new Date();//The current date.
long current_date_in_ms = current_date.getTime();//The current date in milliseconds.
//Take the current date in milliseconds, and subtract 24 hours worth 
//of milliseconds (1000 milliseconds per second, times 60 seconds per 
//minute, times 60 minutes per hour, times 24 hours in a day).
long one_day_ago_in_ms = current_date_in_ms - (1000 * 60 * 60 * 24);
Date one_day_ago = new Date(one_day_ago_in_ms);//Create a new Date object representing one day ago.
//Search all entities with the kind "mail". 
//We create a Filter that requires that the add_date property be greater 
//than the Date we computed above.
Query q = new Query("mail");
Query.Filter date_filter = new Query.FilterPredicate("add_date", Query.FilterOperator.GREATER_THAN_OR_EQUAL, one_day_ago);
q.setFilter(date_filter);
PreparedQuery pq = DatastoreServiceFactory.getDatastoreService().prepare(q);
List<Entity> results = pq.asList(FetchOptions.Builder.withDefaults());

 

An Introduction To The Datastore In Java

Storing Data

Essentially, the datastore is a highly replicated, highly reliable place to store data. However, it is not a SQL database that you may have experience with. Instead, the datastore stores Entities, which are grouped into categories called kinds. Each entity has a unique ID or name – Google App Engine can set a unique ID, or you can set a name in your application code.

To create an entity with a mail kind, we use this line (App Engine allocates a unique ID for us automatically):

Entity entity = new Entity("mail");

Entities can have properties, which are name/valid pairs. To add a property, do this:

entity.setProperty("subject", subject); //Key, then value.

Here’s a complete code example to create an entity, set properties, and store it:

Entity entity = new Entity("mail");//Creates the entity with a kind of "mail", GAE automatically allocates an ID
entity.setUnindexedProperty("from", from);
entity.setProperty("subject", subject);
entity.setProperty("add_date", new Date());//Records the date this entity was added.
DatastoreServiceFactory.getDatastoreService().put(entity);

Note the use of setUnindexedProperty. This method informs App Engine that we won’t be searching on this property, so don’t build a search index for it. This is useful to reduce the cost of storing entities.

Datastore Query

Querying the datastore is simple as well.

Here’s an example piece of code which queries for all Entities with the kind of mail, and requiring that all properties returned have the property add_date greater than the value stored in date_var :

Query q = new Query("mail");
Query.Filter query_filter = new Query.FilterPredicate("add_date", Query.FilterOperator.GREATER_THAN_OR_EQUAL, date_var);
q.setFilter(query_filter);
PreparedQuery pq = DatastoreServiceFactory.getDatastoreService().prepare(q);
List<Entity> results = pq.asList(FetchOptions.Builder.withDefaults());

From here, we can iterate through the List, retrieve each Entity, and conduct operations on each Entity:

for (int i = 0; i < results.size(); i++) {
    Entity entity = results.get(i);
    //Do anything needed with the information from each entity.
}

Deleting

And finally, here is how to delete an entity (entity is the Entity object being deleted).

Key key = entity.getKey();
DatastoreServiceFactory.getAsyncDatastoreService().delete(key);

A Simple index.yaml File

The App Engine SDK developer server can automatically create datastore indexes for your application – just run the datastore querying code within the dev server. But sometimes that isn’t possible.

In that case, you can hand-write your index settings. Here is an example of a simple index.yaml file. It indexes all entities with a kind of Fact, on the property Approved and sorts on the property Add_date in descending order.

indexes:

- kind: Fact
  ancestor: no
  properties:
  - name: Approved
  - name: Add_date
    direction: desc

index.yaml goes in the root directory of your application.

TaskTooLargeError

Google App Engine has an upper limit on how much data you can put into a task – a maximum of 100 KB. This includes everything within an individual task such as parameters, payload, the request URL, etc.

To get around this error, store any large pieces of information within an entity in the datastore. You can then pass the entity’s ID as a task parameter and pull out the entity’s data during task processing.

Optimizing Datastore Use

Google App Engine’s datastore is one of the most underrated parts of the service. Having a relatively cheap (in some cases free) use of a fast, reliable NoSQL store is a terrific deal, especially since most developers are only experienced with SQL databases.

With that said the App Engine datastore can get expensive quickly, especially if it’s being used inefficiently. One of my favorite illustrations of this point is this article. Here’s what I do to optimize my datastore use:

  1. Use .setUnindexedProperty. To set a property on an Entity you call entity.setProperty(key, value). But in the background App Engine is building an index (perhaps multiple indexes) to allow searches on that property. These index builds can get expensive very quickly. If you don’t need to search on a property, use setUnindexedProperty. This informs App Engine that the application will not be searching on that property, so don’t build an index.
  2. Cache data in memcache. Whenever you make a datastore request, copy the returned results into memcache. Then if you need to make the same request, try pulling the data from memcache before querying the datastore again. Memcache use is free so access it before the datastore. Some datastore abstractions – such as Objectify – do this automatically.
  3. If this is a high-traffic app, consider using a backend. A high-memory backend can hold a large amount of data in RAM, and you can transfer data to/from other instances by using URLFetch. As a bonus this technique can be faster than querying entities from the datastore.
  4. Turn off AppStats. If you have AppStats enabled, turn if off for some speed gains. AppStats stores its data in memcache which may cause some of your data to be evicted, causing increased datastore queries and an increased datastore bill.

Retrieving A Datastore Entity With A Key (or Kind Name & ID)

Short code fragment that someone might find useful: retrieve an Entity if you know what the kind and entity ID/name are.

Key key = KeyFactory.createKey("kind", "id/name");
try {
    Entity entity = DatastoreServiceFactory.getDatastoreService().get(key);
} catch (EntityNotFoundException e) {
    //The entity wasn't found. Handle this exception.
}