After reading several books and web pages related to App Engine Datastore, I have decided to write this brief post explaining the basic ideas behind this Datastore, leaning mainly on the book Google App Engine Java and GWT Application Development and information that you can read at https://cloud.google.com/appengine/docs/java/storage.
App Engine Datastore is a schemaless NoSQL datastore with automatic caching, a sophisticated query engine, and atomic transactions. It is based on Google’s Big Table design.
The Datastore’s design has a focus on scalability and it is not a relational database. This design allows its data to be partitioned, or sharded, and it is distributed in a way that makes partitioning data and performing queries extremely efficient.
The Java Datastore SDK provides a supported low-level API for the Datastore. However, the Java SDK also includes third-party implementations of the Java Data Objects(JDO) and Java Persistence API (JPA) interfaces. In addition, the Java SDK includes other third party framewroks such as Objectify and Slim3.
The Datastore holds data objects called entities, which are the basic unit of storage. An entity has a key, and one or more properties, where data is stored. Each property can have one or more values. Property values can belong to a variety of data types, including integers, floating-point numbers, strings, dates, and binary data, among others. After creation, the key cannot be changed. Each entity is identified by its kind, which categorizes the entity for the purpose of queries, and a key that uniquely identifies it within its kind, that is, the kind is reflected in the entity’s key, so that you can always tell the kind of an entity given its key. Although it no entirely accurate, it may be helpful to consider kinds as tables, entities as table rows and properties as table fields or columns.
The key consists of the following components:
- The entity’s kind
- An identifier, which can be either a key name string or an integer
- An optional ancestor path locating the entity within the Datastore hierarchy
When you create an entity, you can optionally designate another entity as its parent; the new entity is a child of the parent entity. You have to take into account that the parent entity need not actually exist. An entity without a parent is a root entity.
Entities in the Datastore can be fetched either by key or by a query on the entity’s properties. The query operates on entities of a given kind; it can specify filters on the entities’ property values, keys, and ancestors, and can return zero or more entities as results. A query can also specify sort orders to sequence the results by their property values. We have to bear in mind that if we construct a query over a kind and the query specified that the results should be ordered by a property, all the recover entities will have a value (even a null value); entities without this property, would not be returned in the query result.
Every Datastore query computes its results using one or more indexes, tables containing entities in a sequence specified by the index’s properties and, optionally, the entity’s ancestors. The indexes are updated incrementally to reflect any changes the application makes to its entities, so that the correct results of all queries are available with no further computation needed.
App Engine predefines a simple index on each property of an entity. An App Engine application can define further custom indexes in an index configuration file named datastore-indexes.xml, which is generated in your application’s /war/WEB-INF/appengine-generated directory.