A Datastore query retrieves entities from Cloud Datastore that meet a specified set of conditions.
A typical query includes the following:
- An entity kind to which the query applies
- Optional filters based on the entities' property values, keys, and ancestors
- Optional sort orders to sequence the results
This page describes the structure and kinds of queries used within App Engine to retrieve data from Cloud Datastore.
A property filter specifies
- A property name
- A comparison operator
- A property value
Filter propertyFilter = new FilterPredicate("height", FilterOperator.GREATER_THAN_OR_EQUAL, minHeight); Query q = new Query("Person").setFilter(propertyFilter);
The property value must be supplied by the application; it cannot refer to or be calculated in terms of other properties. An entity satisfies the filter if it has a property of the given name whose value compares to the value specified in the filter in the manner described by the comparison operator.
The comparison operator can be any of the following (defined as enumerated constants in the nested class
||Less than or equal to|
||Greater than or equal to|
||Not equal to|
||Member of (equal to any of the values in a specified list)|
operator actually performs two queries: one in which all other filters are
unchanged and the
filter is replaced with a
filter, and one where it is replaced with a
filter. The results are then merged, in order. A query can have no more than one
filter, and a query that has one cannot have any other inequality filters.
IN operator also performs multiple
queries: one for each item in the specified list, with all other filters
unchanged and the
IN filter replaced with an
filter. The results are merged in order of the items in the list. If a query has
more than one
IN filter, it is performed as
multiple queries, one for each possible combination of values in the
A single query containing
IN operators is limited to no more than 30
For more information about how
queries translate to multiple queries in a JDO/JPA framework, see the article
Queries with != and IN filters.
To filter on the value of an entity's key, use the special property
Filter keyFilter = new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, lastSeenKey); Query q = new Query("Person").setFilter(keyFilter);
Ascending sorts on
Entity.KEY_RESERVED_PROPERTY are also supported.
When comparing for inequality, keys are ordered by the following criteria, in order:
- Ancestor path
- Entity kind
- Identifier (key name or numeric ID)
Elements of the ancestor path are compared similarly: by kind (string), then by key name or numeric ID. Kinds and key names are strings and are ordered by byte value; numeric IDs are integers and are ordered numerically. If entities with the same parent and kind use a mix of key name strings and numeric IDs, those with numeric IDs precede those with key names.
Queries on keys use indexes just like queries on properties and require custom indexes in the same cases, with a couple of exceptions: inequality filters or an ascending sort order on the key do not require a custom index, but a descending sort order on the key does. As with all queries, the development web server creates appropriate entries in the index configuration file when a query that needs a custom index is tested.
You can filter your Datastore queries to a specified ancestor, so that the results returned will include only entities descended from that ancestor:
Query q = new Query("Person").setAncestor(ancestorKey);
Special query types
Some specific types of query deserve special mention:
A query with no kind and no ancestor filter retrieves all of the entities of an application from Datastore. This includes entities created and managed by other App Engine features, such as statistics entities and Blobstore metadata entities (if any). Such kindless queries cannot include filters or sort orders on property values. They can, however, filter on entity keys by specifying
Entity.KEY_RESERVED_PROPERTY as the property name:
Filter keyFilter = new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, lastSeenKey); Query q = new Query().setFilter(keyFilter);
A query with an ancestor filter limits its results to the specified entity and its descendants:
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); Entity tom = new Entity("Person", "Tom"); Key tomKey = tom.getKey(); datastore.put(tom); Entity weddingPhoto = new Entity("Photo", tomKey); weddingPhoto.setProperty("imageURL", "http://domain.com/some/path/to/wedding_photo.jpg"); Entity babyPhoto = new Entity("Photo", tomKey); babyPhoto.setProperty("imageURL", "http://domain.com/some/path/to/baby_photo.jpg"); Entity dancePhoto = new Entity("Photo", tomKey); dancePhoto.setProperty("imageURL", "http://domain.com/some/path/to/dance_photo.jpg"); Entity campingPhoto = new Entity("Photo"); campingPhoto.setProperty("imageURL", "http://domain.com/some/path/to/camping_photo.jpg"); List<Entity> photoList = Arrays.asList(weddingPhoto, babyPhoto, dancePhoto, campingPhoto); datastore.put(photoList); Query photoQuery = new Query("Photo").setAncestor(tomKey); // This returns weddingPhoto, babyPhoto, and dancePhoto, // but not campingPhoto, because tom is not an ancestor List<Entity> results = datastore.prepare(photoQuery).asList(FetchOptions.Builder.withDefaults());
Kindless ancestor queries
A kindless query that includes an ancestor filter will retrieve the specified ancestor and all of its descendants, regardless of kind. This type of query does not require custom indexes. Like all kindless queries, it cannot include filters or sort orders on property values, but can filter on the entity's key:
Filter keyFilter = new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, lastSeenKey); Query q = new Query().setAncestor(ancestorKey).setFilter(keyFilter);
The following example illustrates how to retrieve all entities descended from a given ancestor:
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); Entity tom = new Entity("Person", "Tom"); Key tomKey = tom.getKey(); datastore.put(tom); Entity weddingPhoto = new Entity("Photo", tomKey); weddingPhoto.setProperty("imageURL", "http://domain.com/some/path/to/wedding_photo.jpg"); Entity weddingVideo = new Entity("Video", tomKey); weddingVideo.setProperty("videoURL", "http://domain.com/some/path/to/wedding_video.avi"); List<Entity> mediaList = Arrays.asList(weddingPhoto, weddingVideo); datastore.put(mediaList); // By default, ancestor queries include the specified ancestor itself. // The following filter excludes the ancestor from the query results. Filter keyFilter = new FilterPredicate(Entity.KEY_RESERVED_PROPERTY, FilterOperator.GREATER_THAN, tomKey); Query mediaQuery = new Query().setAncestor(tomKey).setFilter(keyFilter); // Returns both weddingPhoto and weddingVideo, // even though they are of different entity kinds List<Entity> results = datastore.prepare(mediaQuery).asList(FetchOptions.Builder.withDefaults());
A keys-only query returns just the keys of the result entities instead of the entities themselves, at lower latency and cost than retrieving entire entities:
Query q = new Query("Person").setKeysOnly();
It is often more economical to do a keys-only query first, and then fetch a subset of entities from the results, rather than executing a general query which may fetch more entities than you actually need.
Sometimes all you really need from the results of a query are the values of a few specific properties. In such cases, you can use a projection query to retrieve just the properties you're actually interested in, at lower latency and cost than retrieving the entire entity; see the Projection Queries page for details.
A query sort order specifies
- A property name
- A sort direction (ascending or descending)