| # Query Language |
| |
| > Query examples in this content are shown unencoded to make |
| > them easier to read. Keep in mind that you might need to encode query |
| > strings if you're sending them as part of URLs, such as when you're |
| > executing them with the cURL tool. |
| |
| The following example retrieves a list of restaurants (from a |
| restaurants collection) whose name property contains the value "diner", |
| sorting the list in ascending order by name: |
| |
| /restaurants?ql=select * where name contains 'diner' order by name asc |
| |
| |
| ## Basic syntax |
| |
| Queries of Usergrid data for Apache Usergrid are made up of two kinds of |
| statements: the path to the collection you want to query, followed by |
| the query language statement containing your query. These two statements |
| are separated by "?ql=" to indicate where the query language statement |
| starts. |
| |
| To retrieve items from a collection, you would use a syntax such as the |
| following: |
| |
| /<collection>?ql=<query_statement> |
| |
| In the following example, the query is retrieving all users whose name |
| is Gladys Kravitz. |
| |
| /users?ql=select * where name = 'Gladys Kravitz' |
| |
| The following example selects all items except those that have an a |
| property value of 5: |
| |
| /items?ql=select * where NOT a = 5 |
| |
| Note that there is a shortcut available when your query selects all |
| items matching certain criteria -- in other words, where you use a |
| statement that starts "select \* where". In this case, you can omit the |
| first part of the statement and abbreviate it this way: |
| |
| /items?ql=NOT a = 5 |
| |
| You query your Apache Usergrid data by using a query syntax that's like |
| Structured Query Language (SQL), the query language for relational |
| databases. Unlike a relational database, where you specify tables and |
| columns containing the data you want to query, in your Apache Usergrid |
| queries you specify collections and entities. |
| |
| The syntax of Apache Usergrid queries only *resembles* SQL to |
| make queries familiar and easier to write. However, the language isn't |
| SQL. Only the syntax items documented here are supported. |
| |
| ## Supported operators |
| |
| Comparisons |
| |
| * Less than `<` or `lt` |
| * Less than or equal `<=` or `lte` |
| * Equal `=` or `eq` |
| * Greater than or equal `>=` or `gte` |
| * Greater than `>` or `gt` |
| * Not equal `NOT` |
| |
| Logical operations |
| |
| * Intersection of results `and` |
| * Union of results `or` |
| * Subtraction of results `not` |
| |
| |
| ## Query Response Format |
| |
| the query’s response is formatted in |
| JavaScript Object Notation (JSON). This is a common format used for |
| parameter and return values in REST web services. |
| |
| So for the following query: |
| |
| /users?ql=select * where name = ‘Gladys Kravitz’ |
| |
| ...you would get a response such as the the one below. The JSON format |
| arranges the data in name/value pairs. Many of the values correspond to |
| specifics of the request, including the request’s HTTP action (GET), the |
| application’s UUID, the request’s parameters (the query string you |
| sent), and so on. |
| |
| Here, the query is asking for whole entities in the users collection. |
| Data corresponding to the response is captured in the response’s |
| `entities` array. The array has one member here, corresponding to the |
| one user found by the query (another kind of query might have found more |
| users). That one member gives the UUID of the entity (user), the entity |
| type, and values for properties such as name, username, email, and so |
| on. |
| |
| ```json |
| { |
| "action" : "get", |
| "application" : "8272c9b0-d86a-11e2-92e2-cdf1ce04c1c0", |
| "params" : { |
| "ql" : [ "select * where name = 'Gladys Kravitz'" ] |
| }, |
| "path" : "/users", |
| "uri" : "http://api.usergrid.com/myorg/myapp/users", |
| "entities" : [ { |
| "uuid" : "d0d7d0ba-e97b-11e2-8cef-411c466c4f2c", |
| "type" : "user", |
| "name" : "Gladys Kravitz", |
| "created" : 1373472876859, |
| "modified" : 1373472876859, |
| "username" : "gladys", |
| "email" : "gladys@example.com", |
| "activated" : true, |
| "picture" : "http://www.gravatar.com/avatar/20c57d4f41cf51f2db44165eb058b3b2", |
| "metadata" : { |
| "path" : "/users/d0d7d0ba-e97b-11e2-8cef-411c466c4f2c", |
| "sets" : { |
| "rolenames" : "/users/d0d7d0ba-e97b-11e2-8cef-411c466c4f2c/rolenames", |
| "permissions" : "/users/d0d7d0ba-e97b-11e2-8cef-411c466c4f2c/permissions" |
| }, |
| "connections" : { |
| "firstname" : "/users/d0d7d0ba-e97b-11e2-8cef-411c466c4f2c/firstname", |
| "lastname" : "/users/d0d7d0ba-e97b-11e2-8cef-411c466c4f2c/lastname" |
| }, |
| "collections" : { |
| "activities" : "/users/d0d7d0ba-e97b-11e2-8cef-411c466c4f2c/activities", |
| "devices" : "/users/d0d7d0ba-e97b-11e2-8cef-411c466c4f2c/devices", |
| "feed" : "/users/d0d7d0ba-e97b-11e2-8cef-411c466c4f2c/feed", |
| "groups" : "/users/d0d7d0ba-e97b-11e2-8cef-411c466c4f2c/groups", |
| "roles" : "/users/d0d7d0ba-e97b-11e2-8cef-411c466c4f2c/roles", |
| "following" : "/users/d0d7d0ba-e97b-11e2-8cef-411c466c4f2c/following", |
| "followers" : "/users/d0d7d0ba-e97b-11e2-8cef-411c466c4f2c/followers" |
| } |
| } |
| } ], |
| "timestamp" : 1374694196061, |
| "duration" : 48, |
| "organization" : "myorg", |
| "applicationName" : "myapp", |
| "count" : 1 |
| } |
| ``` |
| |
| Compare the preceding example with the following for another kind of |
| query. Imagine the following request string, where the query string is |
| asking for only the values of two of the entity’s properties (username |
| and name): |
| |
| /users?ql=select username,name where name=’Gladys Kravitz’ |
| |
| In the response JSON from this query, the return value is specified as |
| the property of the `list` item -- here, an array containing only the |
| values of the properties the query asked for, in the order they were |
| requested (username first, then name). |
| |
| { |
| "action" : "get", |
| "application" : "8272c9b0-d86a-11e2-92e2-cdf1ce04c1c0", |
| "params" : { |
| "ql" : [ "select username,name where name='Gladys Kravitz'" ] |
| }, |
| "path" : "/users", |
| "uri" : "http://api.usergrid.com/myorg/myapp/users", |
| "list" : [ [ "gladys", "Gladys Kravitz" ] ], |
| "timestamp" : 1374697463190, |
| "duration" : 25, |
| "organization" : "myorg", |
| "applicationName" : "myapp", |
| "count" : 1 |
| } |
| |
| |
| ## Data types supported in queries |
| |
| As you develop queries for your Apache Usergrid data, remember that entity |
| properties each conform to a particular data type (whether the entity is |
| included by default or an entity you defined). Your queries must |
| acknowledge this, testing with values that conform to each property's |
| data type. (You can view the list of property data types for the default |
| entities at [Default Data Entities](/default-data-entities).) |
| |
| For example, in the default entity `User`, the `name` property is stored |
| as a `string`, the created date as a `long`, and metadata is stored as a |
| JSON object. Your queries must be data type-aware so that you can be |
| sure that query results are as you expect them to be. |
| |
| So imagine you define an entity with a `price` property whose value |
| might be `100.00`. Querying for `100` will return no results even if |
| there are occurrences of `100.00` as `price` values in your data set. |
| That's because the database expected a decimal-delimited `float` value |
| in your query. |
| |
| |
| Data Type Examples Notes |
| ----------- ------------------------------------------------------------------------------------------- --------- |
| `string` `'value'`, `unicode '\uFFFF'`, `octal '\0707'` true | false |
| `long` 1357412326021 Timestamps are typically stored as `long` values. |
| `float` 10.1, -10.1, 10e10, 10e-10, 10E10, 10e-10 Your query must be specific about the value you're looking for, down to the value (if any) after the decimal point. |
| `boolean` true | false |
| `UUID` ee912c4b-5769-11e2-924d-02e81ac5a17b UUID types are typically used for the unique IDs of entities. The value must conform to the following format (do not enclose with quotation marks): xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
| |
| |
| `object` For a JSON object like this one: |
| |
| ``` |
| { |
| "items":[ |
| {"name":"rocks"}, |
| {"name":"boats"} |
| ] |
| } |
| ``` |
| |
| you can use dot notation to reach property values in the object: /mycollection/thing?ql="select * where items.name = 'rocks'" Objects are often used to contain entity metadata, such as the activities associated with a user, the users associated with a role, and so on. |
| |
| ## Retrieving values for multiple properties |
| |
| Your query can return multiple kinds of values -- such as the values of |
| multiple properties -- by specifying the property names in your select |
| statement as a comma-separated list. |
| |
| For example, the following request returns the address and phone number |
| of users whose name is Gladys Kravitz: |
| |
| /users?ql=select address,phone_number where name = 'Gladys Kravitz' |
| |
| |
| ## Querying for the contents of text |
| |
| Your query can search the text of entity values of the string data type. |
| For example, you can search a postal code field for values that start |
| with a specific three numbers. |
| |
| For example, the following query selects all restaurants with the word |
| `diner` in the name: |
| |
| /restaurants?ql=select * where name contains 'diner' |
| |
| **Note:** Not all string properties of the default entities are |
| indexed for searching. This includes the `User` entity's `username` |
| property. |
| |
| This will return all users whose name property contains the word 'Kravitz' |
| |
| /users?ql=select * where name contains 'Kravitz' |
| |
| This will return all users whose name property contains a word beginning with 'Krav' |
| |
| /users?ql=select * where name contains 'Krav*' |
| |
| This will return all users whose name is exactly 'Gladys Kravitz' |
| |
| /users?ql=select * where name = 'Gladys Kravitz' |
| |
| |
| ## Sorting results |
| |
| You can return query results that are sorted in the order you specify. |
| Use the `order by` clause to specify the property to sort by, along with |
| the order in which results should be sorted. The syntax for the clause |
| is as follows `order by <property_name> asc | desc` |
| |
| The following table includes a few examples: |
| |
| /users?ql=select * where lastname = 'Smith' order by firstname asc |
| |
| |
| /users?ql=select * where lastname = 'Smith' order by firstname desc |
| |
| |
| /users?ql=select * where lastname contains 'Sm*' order by lastname asc, firstname asc |
| |
| |
| ## Geoqueries |
| |
| Many of today's apps are enhanced by the use of *geolocation*, wireless |
| detection of the physical location of a remote device. These apps are |
| said to be *geolocation-aware* in that they query the device to |
| determine the user's position and then use this data to further enhance |
| the user's experience. For example, apps can capture the exact location |
| where a picture was taken or a message was created. |
| |
| Usergrid support geolocation on any entity, both built in (e.g., |
| users, groups) and user defined. |
| |
| To add a location to any entity, include the following member to the |
| JSON in a POST or PUT call: |
| |
| "location": { |
| "latitude": 37.779632, |
| "longitude": -122.395131 |
| } |
| |
| For example, to store a listing of restaurants and their locations, |
| start by creating a collection called restaurants: |
| |
| POST https://api.usergrid.com/org_name/app_name/restaurants |
| |
| Next, add a new entity to the collection: |
| |
| POST https://api.usergrid.com/org_name/app_name/restaurants |
| { |
| "name": "Rockadero", |
| "address": "21 Slate Street, Bedrock, CA", |
| "location": { |
| "latitude": 37.779632, |
| "longitude": -122.395131 |
| } |
| } |
| |
| This creates a new restaurant entity called "Rockadero" with the |
| longitude and latitude included as part of the object. |
| |
| When a location is added to an entity, it is easy to make queries |
| against that data. For example, to see all restaurants within a 10 mile |
| radius of the user's location, make a GET call against that entity, and |
| include a search query in the following format: |
| |
| location within <distance in meters> of <latitude>, <longitude> |
| |
| If we use the location of our user Fred, we first need to convert miles |
| to meters. 1 mile is equivalent to 1609.344 meters, so 10 miles is about |
| 16093 meters. Thus, the API call looks like this: |
| |
| GET https://api.usergrid.com/org_name/app_name/restaurants?ql=location within 16093 of 37.776753, -122.407846 |
| |
| |
| ## Managing large sets of results |
| |
| When your query might return more results than you want to display to |
| the user at once, you can use the limit parameter with cursors or API |
| methods to manage the display of results. By default, query results are |
| limited to 10 at a time. You can adjust this by setting the limit |
| parameter to a value you prefer. |
| |
| For example, you might execute a query that could potentially return |
| hundreds of results, but you want to display 20 of those at a time to |
| users. To do this, your code sets the limit parameter to 20 when |
| querying for data, then provides a way for the user to request more of |
| the results when they're ready. |
| |
| You would use the following parameters in your query: |
| |
| +-------------------------+-------------------------+-------------------------+ |
| | Parameter | Type | Description | |
| +=========================+=========================+=========================+ |
| | `limit` | integer | Number of results to | |
| | | | return. The maximum | |
| | | | number of results is | |
| | | | 1,000. Specifying a | |
| | | | limit greater than | |
| | | | 1,000 will result in a | |
| | | | limit of 1,000. | |
| | | | | |
| | | | Limit is applied to the | |
| | | | collection, not the | |
| | | | query string. For | |
| | | | example, the following | |
| | | | query will find the | |
| | | | first 100 entities in | |
| | | | the books collection, | |
| | | | then from that set | |
| | | | return the ones with | |
| | | | author='Hemingway': | |
| | | | | |
| | | | /books?ql=author = | |
| | | | 'Hemingway'&limit=100 | |
| | | | | |
| | | | You can also use the | |
| | | | limit parameter on a | |
| | | | request without a query | |
| | | | string. The following | |
| | | | example is shorthand | |
| | | | for selecting all books | |
| | | | and limiting by 100 at | |
| | | | a time: | |
| | | | | |
| | | | /books?limit=100 | |
| | | | | |
| | | | Using a limit on a | |
| | | | DELETE can help you | |
| | | | manage the amount of | |
| | | | time it takes to delete | |
| | | | data. For example you | |
| | | | can delete all of the | |
| | | | books, 1000 at a time, | |
| | | | with the following: | |
| | | | | |
| | | | DELETE /books?limit | |
| | | | =1000 | |
| | | | | |
| | | | Keep in mind that | |
| | | | DELETE operations can | |
| | | | take longer to execute. | |
| | | | Yet even though the | |
| | | | DELETE query call might | |
| | | | time out (such as with | |
| | | | a very large limit), | |
| | | | the operation will | |
| | | | continue on the server | |
| | | | even if the client | |
| | | | stops waiting for the | |
| | | | result. | |
| +-------------------------+-------------------------+-------------------------+ |
| | `cursor` | string | An encoded | |
| | | | representation of the | |
| | | | query position pointing | |
| | | | to a set of results. To | |
| | | | retrieve the next set | |
| | | | of results, pass the | |
| | | | cursor with your next | |
| | | | call for most results. | |
| +-------------------------+-------------------------+-------------------------+ |
| |
| For example: |
| |
| Select all users whose name starts with fred, and returns the first 50 |
| results: |
| |
| /users?ql=select * where name = 'fred*'&limit=50 |
| |
| Retrieve the next batch of users whose name is "fred", passing the |
| cursor received from the last request to specify where the next set of |
| results should begin: |
| |
| /users?ql=select * where name = 'fred*'&limit=50&cursor=LTIxNDg0NDUxNDpnR2tBQVFFQWdITUFDWFJ2YlM1emJXbDBhQUNBZFFBUUQyMVZneExfRWVLRlV3TG9Hc1doZXdDQWRRQVFIYVdjb0JwREVlS1VCd0xvR3NWT0JRQQ |