Using GQL
GQL is a SQL-like language for retrieving entities or keys from Datastore. While GQL's features are different from those of a query language for a traditional relational database, the GQL grammar is similar to that of SQL.
GQL reference
This page describes building a GQL query, which consists of a GQL query string along with optional named and/or numbered arguments.
For details on the GQL query string itself, you need to see the GQL reference page.
Building a GQL query
The following code snippet shows how to construct and send a simple GQL query:
Node.js (JSON)
function gqlExample(callback) {
datastore.runQuery({
gqlQuery: {
queryString: 'SELECT * FROM Person',
}
}).execute(function(err, result) {
if (!err) {
// Iterate over the results and return the entities.
result = (result.batch.entityResults || []).map(
function(entityResult) {
return entityResult.entity;
});
}
callback(err, result);
});
}
Python (Protocol Buffers)
req = datastore.RunQueryRequest()
gql_query = req.gql_query
gql_query.query_string = 'SELECT * FROM Person'
resp = self.datastore.run_query(req)
results = [entity_result.entity
for entity_result in resp.batch.entity_result]
Java (Protocol Buffers)
// import static com.google.apphosting.client.datastoreservice.client.DatastoreHelper.*;
GqlQuery.Builder query = GqlQuery.newBuilder().setQueryString("SELECT * FROM Person");
RunQueryRequest request = RunQueryRequest.newBuilder().setGqlQuery(query).build();
RunQueryResponse response = datastore.runQuery(request);
List<Entity> results = new ArrayList<Entity>();
for (EntityResult entityResult : response.getBatch().getEntityResultList()) {
results.add(entityResult.getEntity());
}
Tips about GQL behavior
The following table highlights some important aspects of GQL literal values and operators:
Behavior | Example |
---|---|
An integer value is not equal to the
equivalent
double: for example
7
is not equal to
7.0
|
SELECT * WHERE i = 7.0
will never yield an entity with single-valued property
i
with value
7
;
SELECT * WHERE d = 7
will never yield an entity with single-valued property
d
with value
7.0
.
|
Null is a value, not the absence of a value. |
There is no way to determine whether an entity lacks a value for a property (that is, whether the property has no value). If you use a condition of the form
property = NULL
, what will occur is a check whether a null value is explicitly stored for that property. For example,
SELECT * WHERE p = NULL
will never yield an entity with
0
values for property
p
.
|
A
+
immediately followed by an integer literal without a sign, for example
+17
, is always interpreted as an explicitly positive integer, and never as a
+
and an implicitly positive integer. When the latter interpretation is desired, include whitespace between the
+
and the integer literal.
|
|
The operator
=
functions like the
IN or CONTAINS
operators, which can yield some surprising results, especially when used with multi-valued properties.
|
SELECT * WHERE p = 3 AND p = 7
might be expected never to yield any entities, but it is interpreted as
SELECT * WHERE p CONTAINS 3 AND p CONTAINS 7
which may certainly yield entities.
|
Argument binding
Argument binding provide a way for users to specify a value at runtime while at the same time preventing malicious behavior, such as injection attacks.
To specify an argument binding, you specify a binding argument/value pair, similar to this:
Argument | Value |
---|---|
aVal | 13 |
bVal | trisky |
The way you actually do this varies by language, so refer to the argument binding code snippets below for details.
The query string uses
binding sites
to refer to the above bound argument values,
using
@
. For example:
SELECT * WHERE a = @aVal AND b = @bVal
At execution time, this yields
SELECT * WHERE a = 13 AND b = 'trisky'
There are a few usage considerations to keep in mind:
-
Any name may be used as a
binding site
name, although keywords and predefined
name should be avoided; names with leading/trailing double underscore (
__foo__
) are permitted. However, names for an argument binding cannot use names with leading/trailing double underscore. - A given name or number may be used in multiple argument binding sites in a single query string.
-
A query that contains a numbered argument binding site cannot skip any
numbers: for example if you have an argument binding
@2
, you must also have the argument binding@1
; if you have a argument binding@3
, you must also have the argument bindings@1
and@2
, and so forth. You don't have to use them in any particular order, but they must all be present.
Argument binding sample
The following snippets shows how to use argument binding with named arguments:
Node.js (JSON)
function gqlNamedArgsExample(callback) {
datastore.runQuery({
gqlQuery: {
queryString: 'SELECT * FROM Person WHERE height >= @minHeight AND height <= @maxHeight',
nameArgs: [{ name: 'minHeight', value: { integerValue: 48 } },
{ name: 'maxHeight', value: { integerValue: 60 } }]
}
}).execute(function(err, result) {
if (!err) {
// Iterate over the results and return the entities.
result = (result.batch.entityResults || []).map(
function(entityResult) {
return entityResult.entity;
});
}
callback(err, result);
});
}
Python (Protocol Buffers)
req = datastore.RunQueryRequest()
gql_query = req.gql_query
query_string = ('SELECT * FROM Person WHERE height >= @minHeight '
'AND height <= @maxHeight')
gql_query.query_string = query_string
query_arg = gql_query.name_arg.add()
query_arg.name = 'minHeight'
query_arg.value.integer_value = 48
query_arg = gql_query.name_arg.add()
query_arg.name = 'maxHeight'
query_arg.value.integer_value = 60
resp = self.datastore.run_query(req)
results = [entity_result.entity
for entity_result in resp.batch.entity_result]
Java (Protocol Buffers)
// import static com.google.apphosting.client.datastoreservice.client.DatastoreHelper.*;
GqlQuery.Builder query = GqlQuery.newBuilder()
.setQueryString("SELECT * FROM Person WHERE height >= @minHeight AND height <= @maxHeight");
query.addNameArgBuilder().setName("minHeight").setValue(makeValue(48));
query.addNameArgBuilder().setName("maxHeight").setValue(makeValue(60));
RunQueryRequest request = RunQueryRequest.newBuilder().setGqlQuery(query).build();
RunQueryResponse response = datastore.runQuery(request);
List<Entity> results = new ArrayList<Entity>();
for (EntityResult entityResult : response.getBatch().getEntityResultList()) {
results.add(entityResult.getEntity());
}
The following snippets shows how to use argument binding with numbered arguments:
Node.js (JSON)
function gqlNumberedArgsExample(callback) {
datastore.runQuery({
gqlQuery: {
queryString: 'SELECT * FROM Person WHERE height >= @1 AND height <= @2',
numberArgs: [{ value: { integerValue: 48 } },
{ value: { integerValue: 60 } }]
}
}).execute(function(err, result) {
if (!err) {
// Iterate over the results and return the entities.
result = (result.batch.entityResults || []).map(
function(entityResult) {
return entityResult.entity;
});
}
callback(err, result);
});
}
Python (Protocol Buffers)
req = datastore.RunQueryRequest()
gql_query = req.gql_query
query_string = 'SELECT * FROM Person WHERE height >= @1 AND height <= @2'
gql_query.query_string = query_string
gql_query.number_arg.add().value.integer_value = 48
gql_query.number_arg.add().value.integer_value = 60
resp = self.datastore.run_query(req)
results = [entity_result.entity
for entity_result in resp.batch.entity_result]
Java (Protocol Buffers)
// import static com.google.apphosting.client.datastoreservice.client.DatastoreHelper.*;
GqlQuery.Builder query = GqlQuery.newBuilder()
.setQueryString("SELECT * FROM Person WHERE height >= @1 AND height <= @2");
query.addNumberArgBuilder().setValue(makeValue(48));
query.addNumberArgBuilder().setValue(makeValue(60));
RunQueryRequest request = RunQueryRequest.newBuilder().setGqlQuery(query).build();
RunQueryResponse response = datastore.runQuery(request);
List<Entity> results = new ArrayList<Entity>();
for (EntityResult entityResult : response.getBatch().getEntityResultList()) {
results.add(entityResult.getEntity());
}
Using literals sample code
The following snippet shows the use of literals:
Node.js (JSON)
function gqlLiteralExample(callback) {
datastore.runQuery({
gqlQuery: {
queryString: 'SELECT * FROM Person WHERE height >= 48 AND height <= 60',
allowLiteral: true
}
}).execute(function(err, result) {
if (!err) {
// Iterate over the results and return the entities.
result = (result.batch.entityResults || []).map(
function(entityResult) {
return entityResult.entity;
});
}
callback(err, result);
});
}
Python (Protocol Buffers)
req = datastore.RunQueryRequest()
gql_query = req.gql_query
query_string = 'SELECT * FROM Person WHERE height >= 48 AND height <= 60'
gql_query.query_string = query_string
gql_query.allow_literal = True
resp = self.datastore.run_query(req)
results = [entity_result.entity
for entity_result in resp.batch.entity_result]
Java (Protocol Buffers)
// import static com.google.apphosting.client.datastoreservice.client.DatastoreHelper.*;
GqlQuery.Builder query = GqlQuery.newBuilder()
.setQueryString("SELECT * FROM Person WHERE height >= 48 AND height <= 60");
query.setAllowLiteral(true);
RunQueryRequest request = RunQueryRequest.newBuilder().setGqlQuery(query).build();
RunQueryResponse response = datastore.runQuery(request);
List<Entity> results = new ArrayList<Entity>();
for (EntityResult entityResult : response.getBatch().getEntityResultList()) {
results.add(entityResult.getEntity());
}