Data Store

The simplest use case of Kinvey is storing and retrieving data to and from your cloud backend.

The basic unit of data is an entity and entities of the same kind are organized in collections. An entity is a set of key-value pairs which are stored in the backend in JSON format. Kinvey's libraries automatically translate your native objects to JSON.

Kinvey's data store provides simple CRUD operations on data, as well as powerful filtering and aggregation.

The Appdata API forms one of the core REST services provided by the Kinvey backend.

Entities

Entities are the basic unit of data, stored as data objects using a JSON representation in the backend. The full set of CRUD operations is available for manipulating entities.

Create

Stores the JSON document passed in the request body at the specified path. If an _id is specified, the request will overwrite any existing entity with the same _id. If an _id is not specified, one will be automatically generated. The response will be HTTP 201 Created with a Location header containing the URL for future updates.

This request allows only a single entity to be uploaded. For bulk upload, see the CSV/JSON import feature on the Kinvey console (navigate to the collection, click Settings, then click Import Data).

Entities can be created either using a POST request:

POST /appdata/:appKey/:collectionName HTTP/1.1
Host: baas.kinvey.com
Authorization: [user credentials]
Content-Type: application/json

<JSON-Document-representing-Entity>
HTTP/1.1 201 OK
Content-Type: application/json

<JSON-Document-representing-Entity>

Or using a PUT request, and including the entity's id in the path:

PUT /appdata/:appKey/:collectionName/:id HTTP/1.1
Host: baas.kinvey.com
Authorization: [user credentials]
Content-Type: application/json

<JSON-Document-representing-Entity>
HTTP/1.1 201 OK
Content-Type: application/json

<JSON-Document-representing-Entity>

Required headers

  • Authorization
  • Content-Type: application/json

Retrieve

A GET to /appdata/:appKey/:collectionName/:id, lets an app retrieve a previously created entity.

GET /appdata/:appKey/:collectionName/:id HTTP/1.1
Host: baas.kinvey.com
Authorization: [user credentials]
HTTP/1.1 200 OK
Content-Type: application/json

<JSON-Document-representing-Entity>

Results from a single GET query are limited to 10,000 entities. If your query produces more than that number of matching entities, only the first 10,000 will be returned.

Required headers

  • Authorization

Update

A PUT to /appdata/:appKey/:collectionName/:id, lets an app update a previously created entity.

Currently there is no way to pass only the attributes you want changed. The entire JSON body is stored as passed in the request body.

PUT /appdata/:appKey/:collectionName/:id HTTP/1.1
Host: baas.kinvey.com
Authorization: [user credentials]
Content-Type: application/json

<JSON-Document-representing-Entity>
HTTP/1.1 200 OK
Content-Type: application/json

<JSON-Document-representing-Entity>

Required headers

  • Authorization
  • Content-Type: application/json

Delete

Deletes an explicity identified entity located at the specified URI or multiple entities in the collection filtered using a query.

When using API version 1 or below, the delete operation returns a '204 No Content' response.

DELETE /appdata/:appKey/:collectionName/:id?query=... HTTP/1.1
Host: baas.kinvey.com
X-Kinvey-API-Version: 1
Authorization: [user credentials]
HTTP/1.1 204 No Content

Starting wth API version 2, a delete returns a '200 OK' with a count of the number of entities deleted in the response body.

DELETE /appdata/:appKey/:collectionName/?query=... HTTP/1.1
Host: baas.kinvey.com
X-Kinvey-API-Version: 2
Authorization: [user credentials]
HTTP/1.1 200 OK
Content-Type: application/json

{ 
  "count": 5 
}

Required headers

  • Authorization

Deleting a collection

To permanently delete an entire collection, send a POST request containing the name of the collection you wish to delete to /rpc/:appKey/remove-collection. To ensure that this destructive action is not performed accidentally, you must authenticate using the master secret, as well as include the X-Kinvey-Delete-Entire-Collection header as part of the request.

POST /rpc/:appKey/remove-collection HTTP/1.1
Host: baas.kinvey.com
Content-Type: application/json
Authorization: [master credentials]
X-Kinvey-API-Version: 2
X-Kinvey-Delete-Entire-Collection: true

{
  "collectionName": "your-collection-name"
}

If the collection was successfully deleted, Kinvey will respond with a '200 OK', with a body containing the number of collections deleted, which will always be 1.

HTTP/1.1 200 OK
Content-Type: application/json

{ 
  "count": 1
}

Required headers

  • Authorization
  • X-Kinvey-Delete-Entire-Collection: true
  • Content-Type: application/json

Metadata

Every entity has a _kmd (Kinvey Metadata) JSON object associated with it, which provides meta-information about an entity. The format of this object is:

"_kmd": {
  "lmt": "2013-03-14T15:55:00.329Z",
  "ect": "2013-03-14T15:55:00.329Z"
}

The object exposes the following properties:

  • lmt (last modified time) - holds the time the entity was last updated on the server.
  • ect (entity creation time) - holds the time the entity was created on the server. This property will be added to an entity when it is created using POST or PUT, and will remain unchanged for the life of the entity.

Querying

Kinvey's REST API is backed by MongoDB. This gives you access to the power of MongoDB's query language, exposed through the ?query={} URL parameter. Similarly, you have access to the power of MongoDB's aggregation features.

For example, an HTTP GET request to

/appdata/:appKey/:collectionName/?query=[filters]&[modifiers]

retrieves a subset of documents that match the criteria specified via filters and modifiers.

When sending queries to Kinvey's REST API, an app needs to URLEncode the query strings, which most tools and libraries easily support. For readability, we don't do that in the examples below.

Filters

Filters allow an app to specify a range of MongoDB query predicates for filtering data stored in the collection. Queries respect Kinvey's access control settings as well, and will only retrieve entities to which the authenticated user has access.

Query basics

To query for a single property with a specific value, use a JSON object of the form {"propertyName":"value"}:

?query={"firstName":"James"}
?query={"age":15}

To query for nested JSON sub-objects, use the dot notation. For example, if the entity contains the following JSON:

{
  "_id": "12345",
  "author": {
    "firstName": "Terry",
    "lastName": "Pratchett"
  }
}

It can be retrieved by the following query:

?query={"author.firstName":"Terry"}

Logical operators

You can filter by more than one condition using a single query. Separating your queries with a comma (,) will perform an implicit logical AND operation -- in other words, the query will return any entities that match ALL of the conditions. For example, the query below will return an entity with a first name of James and a last name of Bond, but will not return an entity with a first name of James and a last name of Smith.

?query={"firstName":"James", "lastName":"Bond"}

You may also use explicit logical AND and OR operators. For example, the query above can also be written as:

?query={"$and":[{"firstName":"James", "lastName":"Bond"}]}

Similarly, to perform a logical OR, use the $or operator. The following query will return all entities that have a first name of James (even if the last name is not Bond), as well as all entities having a last name of Bond (even if the first name is not James):

?query={"$or":[{"firstName":"James", "lastName":"Bond"}]}

For more information on logical operators, see the MongoDB reference documentation.

Comparison operators

MongoDB supports several comparison operators, used to compare values in entities. For example, the following query will find any entities having an age that is greater than or equal to 31 by using the $gte operator:

?query={"age":{"$gte": 31}}

Also available are $gt (greater than), $lt (less than) and $lte (less than or equal), among others. For a complete list of supported comparison operators, see the MongoDB documentation.

Modifiers

Modifiers allow an app to change the results of a query. They are included as URL parameters to the request, and have various effects on the result set of your queries. For example, an app can use modifiers to limit the size of the result set, implement pagination, or extract a subset of entity properties into the response.

Supported modifiers

Kinvey supports the following modifiers:

limit - set a maximum number of results to return. Examples:

# find the first 5 entities in the collection
?query={}&limit=5

# find only the first 10 entities with first name James
?query={"firstName":"James"}&limit=10

sort - sort the result set by one or more properties. Examples:

# sort results by age (ascending)
?query={}&sort=age
# or, equivalently
?query={}&sort={"age": 1}

# sort results by age (descending)
?query={}&sort={"age": -1}

# find all entities with the first name James, and sort results by
# first name (ascending), and then by last name (descending) -- "James Zoo" will
# come before "James Bond", but "Abraham Lincoln" will come before both
?query={"firstName":"James"}&sort={"firstName": 1, "lastName": -1}

fields - only return a certain set of properties from matching entities. Examples:

# only retrieve the age and lastName fields of matching documents
?query={}&fields=age,lastName

# only retrieve the ages of people named James
?query={"firstName":"James"}&fields=age

Certain fields that are essential to each entity will always be returned, even if they are not included in a fields modifier. These include _id, _acl and _kmd.

skip - skips the first N results that match the query. Example:

# find the second youngest person with the first name James
?query={"firstName":"James"}&sort={"age":1}&limit=1&skip=1

# find everyone except for the 10 oldest people
?query={}&sort={"age":-1}&skip=10

Using a combination of the skip and limit operators is a common way of "paging" through result sets -- that is, returning small chunks of results instead of the entire set at once. For example, the following set of requests page a result, returning 20 entities at a time:

?query={}&limit=20&skip=0
?query={}&limit=20&skip=20
?query={}&limit=20&skip=40

Results from a single GET query are limited to 10,000 entities. Even if your query includes a limit of more than 10,000, if your query produces more than that number of matching entities, only the first 10,000 will be returned.

Restrictions and limitations

Kinvey enforces several restrictions on queries.

Regular expressions

Regular expressions need to be anchored (prefixed with ^), and case sensitive. To do case insensitive search, create a normalized (i.e. all lowercase) field in your collection and perform the match on that field.

Disallowed operators

The $where and $query operators are not supported, and using them will result in an error.

Result set limits

  • Any query submitted to the REST API will return a maximum of 10,000 results. If your query matches more than 10,000 entities, only the first 10,000 will be returned.

  • A single query can only retrieve 100mb of data, and will return an error if this limit is exceeded. Retrieving a very large amount of data can place a heavy burden on an app, and we encourage you to reconsider your design if you are hitting this limit. If your app absolutely needs to retrieve more than 100mb of data, please consider using pagination.

Counting

To count the number of objects in a collection, make a GET to _count.

GET /appdata/:appKey/:collectionName/_count HTTP/1.1
Host: baas.kinvey.com
Authorization: [user credentials]
HTTP/1.1 200 OK
Content-Type: application/json

{"count": <count-of-entities>}

This means that an app won't be able to save an entity with id of _count. ids that start with underscore are a reserved namespace.

Note that an app will get a {"count": 0} if the collection doesn't exist.

Required headers

  • Authorization

Aggregation

To perform a SQL-style GROUP BY aggregation, make a POST to _group. The request body should contain a JSON object with four properties:

  • key: an object that selects the field to group by
  • initial: an object containing the initial structure of the document to be returned
  • reduce: a JavaScript function that will be used to reduce down the result set
  • condition: an optional filter applied to the result set before it is fed to the MapReduce operation

These are generally a little more complex than SQL GROUP BY, but an example goes a long way. Here, we groups the entities by lastName, applying the age filter, and return the count in each group.

POST /appdata/:appKey/:collectionName/_group HTTP/1.1
Host: baas.kinvey.com
Authorization: [user credentials]
Content-Type: application/json

{
  "key": {
    "lastName":true
  },
  "initial": {
    "count": 0
  },
  "reduce": "function(doc,out){ out.count++;}",
  "condition": {
    "age": { "$gt":31 }
  }
}
[
  {
    "lastName": "Bond",
    "count": 1
  }
  {
    "lastName": "Jones",
    "count": 3
  }
]

Required headers

  • Authorization
  • Content-Type: application/json

Location Querying

See the Location guide for information on how to query data by location.

Related Samples

Got a question?