This documentation is about manipulating data from your Android code. This requires you to create a pair of API keys and configure them in your main activity. If you want to user server-side logic you should go to the Server-side logic section of the documentation.
You make queries using Query
objects. You create them using the Backbeam.select()
method passing the entity identifier. It is optional to set a BQL query using setQuery()
. Then you fetch the results calling fetch()
with three arguments:
limit
The maximum number of elements to fetchoffset
The offset of the querycallback
The callback handler to handle the query resultThe setQuery()
method receives a Stirng containing a BQL query. If the BQL query needs parameters you pass them to the method just separating them with commas.
q.setQuery("where name like ? and score > ?", "awesome", 100);
All operations that need to send or receive information fromt the server are handled asynchronously. If the operation receives information you provide a callback. Since Java doesn't support closures yet, you normally will pass an object of an anonymous class created inline. These callbacks usually have a success()
method that you must implement and optionally you can override a failure()
method.
Backbeam.select("place").setQuery("sort by created_at").fetch(100, 0, new FetchCallback() {
@Override
public void success(List<BackbeamObject> objects, int totalCount, boolean fromCache) {
for (BackbeamObject object : objects) {
// Do something with this object
System.out.println("object "+object.getString("name"));
}
}
});
In this case the success()
method receives three arguments
Queries can be cached in different ways. Before fetching the result of a query you can set the query fetch policy calling the setFetchPolicy()
method. There are a few fetch policies available:
No matter what policy you use either success()
or failure()
are guaranteed to be called at least once.
If you need to remove several objects at once and they share common constraints you can create a query and then call one of these methods... You can remove a limited number of objects:
Query query = Backbeam.select("some-entity").setQuery(...);
query.remove(10, 0, new RemoveCallback() {
@Override
public void success(int removed) {
// Here the first 10 objects matching the query have been removed
}
});
Or you can remove all objects matching the query
Query query = Backbeam.select("some-entity").setQuery(...);
query.removeAll(new RemoveCallback() {
@Override
public void success(int removed) {
// Here the objects have been removed. You can get the number of removed objects
}
});
`
There is a helper object to create collection constraints when using the in operator in a query.
CollectionConstraint collection = new CollectionConstraint();
collection.addTwitterIdentifier(someTwitterIdentifier);
collection.addObject(new BackbeamObject("user", someBackbeamIdentifier));
collection.addEmailAddress("user@example.com");
Query query = new Query("user");
query.setQuery("where this in ?", collection);
query.fetch(100, 0, new FetchCallback() {
@Override
public void success(List objects, int totalCount,
boolean fromCache) {
System.out.println("objects: "+objects.size());
}
});
As you can see in the collection constraint you can use Backbeam objects. This applies to any entity in your data model. If you are querying users you can also use Twitter, Facebook, Google+, LinkedIn or Twitter identifiers as well as email addresses.
To create or update objects you use the save()method. To create a new object first you need to instantiate an empty object passing the entity name to which this object will be a member of.
BackbeamObject obj = new BackbeamObject("place");
obj.setString("name", "A new place");
obj.save(new ObjectCallback() {
@Override
public void success(BackbeamObject object) {
System.out.println("created! :) "+object.getId());
}
});
setString(String fieldName, String value)
Sets the value of a text fieldsetDate(String fieldName, Date value)
Sets the value of a date fieldsetNumber(String fieldName, Number value)
Sets the value of a numeric fieldincrementNumber(String fieldName, int value)
Increments the value of a numeric fieldsetLocation(String fieldName, Location value)
Sets the value of a "location" fieldsetBoolean(String fieldName, boolean value)
Sets the value of a boolean fieldsetDay(String fieldName, GregorianCalendar value)
Sets the value of a "day" field. You can pass a Gregorian calendar. You can also pass a java.util.Date and the current calendar's timezone will be used to calculate the year, month and day.setObject(String fieldName, BackbeamObject value)
Sets the value of a relationship "to-one"If you want to update an object of which you know the identifier but you don't have an instance of it you can pass the identifier to the BackbeamObject
constructor
When an object is created or updated the server saves the changes you made and sends you any other change that could been made to that object. So inside the success()
method the object is fully synchronized.
BackbeamObject obj = new BackbeamObject("place", identifierYourAlreadyKnow);
obj.setString("name", "A new name for that palce");
obj.save(new ObjectCallback() {
@Override
public void success(BackbeamObject object) {
// here you can access any field of 'object'
}
});
To add or remove objects of a relationship "to-many" you will use the methods removeObject(String fieldName, BackbeamObject object)
and addObject(String fieldName, BackbeamObject object)
. For example:
BackbeamObject user = ...;
user.addObject("friends", myNewFriend);
user.removeObject("friends", userThatIsNoLongerMyFriend);
user.save(new ObjectCallback() {
@Override
public void success(BackbeamObject object) {
// ...
}
});
If you have an object instance and you need to fill it with the latest changes on the server without making you new changes then you use the refresh() method.
BackbeamObject obj = someObjectYouAlreadyHaveInstantiated;
obj.refresh(new ObjectCallback() {
@Override
public void success(BackbeamObject object) {
// here you can access any field of 'object'
}
});
The refresh()
method is overloaded and accepts an optional first parameter that is part of a BQL query. In this parameter you can specify to join some relationships while synchronizating the state of this object.
BackbeamObject obj = someObjectYouAlreadyHaveInstantiated;
obj.refresh("join some-relationship", new ObjectCallback() {
@Override
public void success(BackbeamObject object) {
// here you can access any field. You can also access the joined relationship
JoinResult result = object.getJoinResult("some-relationship")
}
});
If you need to read an object of which you know its identifier and you don't already instantiated it then you can use Backbeam.read()
.
Backbeam.read("place", id, new ObjectCallback() {
@Override
public void success(BackbeamObject object) {
// ...
}
});
The first argument is the entity identifier, the second is the unique identifier of that object and finally you pass the callback that will be called when the operation is complete. You can optionally pass a parameter that is part of a BQL query to join some relationships.
There is a special kind of entity that lets you hold files. It is the file
entity. The entity itself holds information about the type of file, size, etc. If you need the download the content of the file you need to generate a URL. There is a special method called composeFileURL
to which you can pass parameters. For example if you want to download an image you can transform it indicating a width and/or height. You can also pass null
to this method.
TreeMap<String, Object> options = new TreeMap<String, Object>();
options.put("width", 40);
options.put("height", 40);
String url = fileObject.composeFileURL(options);
`
Note that the file object should have their properties loaded. Specially file
objects have a version
field that is required to generate the URL. This field changes everytime the file content changes. This way the URL changes everytime the content changes and there are no problems with any cache. In summary, be sure that the file has its version field loaded. You can't do a refresh if it is not loaded. And if the file object is the result of a query be sure to use a join on the relationship. See this example:
Backbeam.select("company").setQuery("join logo").fetch(100, 0, new FetchCallback() {
@Override
public void success(List<BackbeamObject> companies, int totalCount, boolean fromCache) {
for (BackbeamObject company : companies) {
BackbeamObject logo = company.getObject("logo");
String logoURL = logo.composeFileURL(null);
// Do something with logoURL
}
}
});
For images it is recommended to use an external library such as Android Universal Image Loader to handle images efficiently.
To createa a file
from you Java code you can use the uploadFile
method. This creates a new object in the database and uploads the content passed in the FileUpload
object. There are two ways of creating a FileUpload
object.
new FileUpload(File file, String mimeType)
new FileUpload(InputStream inputStream, String filename, String mimeType)
Let's see a complete example:
BackbeamObject object = new BackbeamObject("file");
object.uploadFile(new FileUpload(stream, "image.png", "image/png"), new ObjectCallback() {
@Override
public void success(BackbeamObject object) {
System.out.println("success!! "+object.getId());
}
@Override
public void failure(BackbeamException exception) {
System.out.println("failure!");
exception.printStackTrace();
}
});
You can perform geoqueries on entities having at least one field whose type is set to location. There are two types of geolocated queries: you can query the closest objects to a given point or you can query the objects inside a bounding box.
To query objects near to a given location you need to tell the SDK the name of the field whose type is location, the coordinates of the point (latitude + longitude), and the maximum number of results you want to fetch. The success block is very similar to a regular success query block but it returns additionally the distances of the objects to the location used to query the data. The distances are measured in meters.
Query query = new Query("place");
query.near("location", 41.641113, -0.895115, 10, new NearFetchCallback() {
@Override
public void success(List<BackbeamObject> objects, int totalCount,
List<Integer> distances, boolean fromCache) {
// Success
}
});
To query objects inside a bounding box you need to tell the SDK the name of the field whose type is location, the south-west and north-east coordinates of the corners of the bounding box, and the maximum number of results you want to fetch. The success block is exactly the same to any regular success query block.
Query query = new Query("place");
query.bounding("location", 41.641113, -0.902896, 41.645883, -0.895115, 10, new FetchCallback() {
@Override
public void success(List<BackbeamObject> objects, int totalCount,
boolean fromCache) {
// Success
}
});