To write data into a [[service]] application database, three methods are available:
Method Description set() This method (over)writes data at a data node of the database. update() This method updates one or more child nodes of a given data node without overwriting it as a whole. push() This method adds a child node to a given data node, with a unique and chronological ID. It is particularly useful to build lists of data (e.g. chat messages within a chat room).
Writing data using set()
The set() method writes new data into the data node on which it is applied. If it already contains data, all data at this node (including any child nodes) will be overwritten.
As an example related to an address book application, let's start by saving some contact details. Each contact contains a unique userName, as well as a firstName, a lastName, a phoneNumber, an email and a birthday.
First, we get the root data node of our [[service]] application database, where to save our contact details. Our application is called "webcom-addressbook":
var adbk = new Webcom("webcom-addressbook");
Webcom adbk = new Webcom(new WebcomApp("webcom-addressbook"));
var adbk : WCWebcom = WCWebcom(url:"[[baseUrl]]/base/webcom-addressbook")!
Then we use the set() method to create an object under the "contacts" node.
In our application, this object is intended to represent a contact within our address book and consists in a child node named by the userName of this contact, which in turn has one child node for each attribute of the contact: firstName, lastName, phoneNumber, email and birthday. This object is actually made of a JSON object whose unique key is the userName with another JSON object as value, whose properties are key-value pairs for all other attributes listed above.
The set() method accepts strings, numbers, booleans, null
, arrays or JSON objects. Passing null
to it actually removes the data at the node on which it is called. In our example we simply pass the JSON object representing our contact details:
var contacts = adbk.child("contacts"); // get a reference on the "contacts" data node
var maccaContact = { // our JSON object representing the contact details for "macca"
macca: {
birthday: "June 18, 1942",
firstName: "Paul",
lastName: "McCartney",
phoneNumber: "020 1234 6541",
email: "paulo@apple.com"
}
};
contacts.set(maccaContact);
Webcom contacts = adbk.child("contacts"); // get a reference on the "contacts" data node
HashMap maccaContact = new HashMap() { // our JSON object representing the contact details for "macca"
{ put("macca", new HashMap() {
{ put("birthday", "June 18, 1942"); }
{ put("firstName", "Paul"); }
{ put("lastName", "McCartney"); }
{ put("phoneNumber", "020 1234 6541"); }
{ put("email", "paulo@apple.com"); }
});
}
};
contacts.set(maccaContact);
let contacts : WCWebcom = adbk.child("contacts")! // get a reference on the "contacts" data node
let maccaContact = [ "macca": [ // our JSON object representing the contact details for "macca"
"birthday": "June 18, 1942",
"firstName": "Paul",
"lastName": "McCartney",
"phoneNumber": "020 1234 6541",
"email": "paulo@apple.com"
]
]
contacts.set(maccaContact as NSObject)
As the database relies on a tree-like structure, we could also have saved the contact properties directly on the "macca" child node:
var contact = adbk.child("contacts/macca");
contact.set({
birthday: "June 18, 1942",
firstName: "Paul",
lastName: "McCartney",
phoneNumber: "020 1234 6541",
email: "paulo@apple.com"
});
Webcom contact = adbk.child("contacts/macca");
contact.set(new HashMap() {
{ put("birthday", "June 18, 1942"); }
{ put("firstName", "Paul"); }
{ put("lastName", "McCartney"); }
{ put("phoneNumber", "020 1234 6541"); }
{ put("email", "paulo@apple.com"); }
});
let contact : WCWebcom = adbk.child("contacts/macca")
contact?.set([
"birthday" : "June 18, 1942",
"firstName" : "Paul",
"lastName" : "McCartney",
"phoneNumber" : "020 1234 6541",
"email" : "paulo@apple.com"
] as NSObject)
Both examples result in the same database with the following content:
{
"contacts": {
"macca": {
"birthday": "June 18, 1942",
"firstName": "Paul",
"lastName": "McCartney",
"phoneNumber": "020 1234 6541",
"email": "paulo@apple.com"
}
}
}
If some data already existed at the "contact" node (typically some already existing contacts), then
- the first piece of code would overwrite the node as whole, erasing all pre-existent child nodes.
- the second piece of code would overwrite only the "macca" sub-node, preserving the data of all other child nodes of the "contact" node.
Writing data using update()
The update() method makes it possible to update several child nodes of a given data node at a time. When called on a node, it overwrites each child node of this node, according to each key-value pair of the JSON object passed as argument.
In this way, if we replace set()
with update()
within one of the example above, we complete the child nodes of the "contacts" node instead of overwriting it:
var contacts = adbk.child("contacts"); // get a reference on the "contacts" data node
var lennonContact = { // our JSON object representing the contact details for a new "lennon" child node
lennon: {
birthday: "October 9, 1940",
firstName: "John",
lastName: "Lennon",
email: "johnandyoko@apple.com"
}
};
contacts.update(lennonContact);
Webcom contacts = adbk.child("contacts"); // get a reference on the "contacts" data node
HashMap lennonContact = new HashMap() { // our JSON object representing the contact details for a new "lennon" child node
{ put("lennon", new HashMap() {
{ put("birthday", "October 9, 1940"); }
{ put("firstName", "John"); }
{ put("lastName", "Lennon"); }
{ put("email", "johnandyoko@apple.com"); }
});
}
};
contacts.update(lennonContact);
let contacts : WCWebcom = adbk.child("contacts")! // get a reference on the "contacts" data node
let lennonContact = [ "lennon": [ // our JSON object representing the contact details for a new "lennon" child node
"birthday": "October 9, 1940",
"firstName": "John",
"lastName": "Lennon",
"email": "johnandyoko@apple.com"
]
]
contacts.update(lennonContact as NSObject)
As a result, when the set
and update
examples are run sequentially, the database content looks like:
{
"contacts": {
"macca": {
"birthday": "June 18, 1942",
"firstName": "Paul",
"lastName": "McCartney",
"phoneNumber": "020 1234 6541",
"email": "paulo@apple.com"
},
"lennon": {
"birthday": "October 9, 1940",
"firstName": "John",
"lastName": "Lennon",
"email": "johnandyoko@apple.com"
}
}
}
Using a completion callback with set()
or update()
methods
The methods set() and update() additionally accept an optional completion callback that is called when the write has been committed on the [[service]] servers.
For example in the previous case, if you would like to know when your contact's data has been committed, you can add a completion callback. When the data writing fails for some reason, the callback is called with an error object describing the failure. When the data is successfully committed, the callback is called with no error object.
contacts.set(maccaContact, function(error) {
if (error) {
alert("macca contact could not be saved: " + error);
} else {
contacts.update(lennonContact, function(error) {
if (error) {
alert("lennon contact could not be saved: " + error);
} else {
alert("all contacts have been saved!");
}
});
}
});
contacts.set(maccaContact, new OnComplete() {
@Override
public void onComplete() {
contacts.update(lennonContact, new OnComplete() {
@Override
public void onComplete() {
// all contacts have been saved
}
@Override
public void onError(WebcomError error) {
// lennon contact could not be saved.
}
});
}
@Override
public void onError(WebcomError error) {
// macca contact could not be saved.
}
});
contacts.set(maccaContact as NSObject) { (error) in
if ((error) != nil) {
print("macca contact could not be saved: \(error.debugDescription)")
} else {
contacts.update(lennonContact as NSObject) { (error) in
if ((error) != nil) {
print("lennon contact could not be saved: \(error.debugDescription)")
} else {
print("all contacts have been saved!")
}
}
}
}
Saving a list of data using push()
In our address book example, we could imagine that the address book is shared between several users. If a user adds a new contact it will be stored in the database. But in a shared address book many users may add contacts at the same time. If two users write simultaneously contacts into the "contacts" node, then one of the contact would be deleted by the other.
To solve this problem, Webcom provides the method push(). This method returns a new child node with a unique ID and sets some data on this newly created node (using the set() method). The generated ID is based on a timestamp, so that the IDs of the of created child nodes are ordered chronologically. When using this method, several users can add children to the same data node of a database at the same time without any write conflict.
In the following example we add contacts to our shared address book using the push() method :
var otherContacts = adbk.child("other_contacts");
otherContacts.push({
birthday: "February 25, 1943",
firstName: "George",
lastName: "Harrisson",
phoneNumber: "020 1234 8879"
});
otherContacts.push({
birthday: "July 7, 1940",
firstName: "Ringo",
lastName: "Starr",
phoneNumber: "020 1234 4561"
});
var otherContacts = adbk.child("other_contacts");
otherContacts.push(new HashMap() {
{ put("birthday", "February 25, 1943"); }
{ put("firstName", "George"); }
{ put("lastName", "Harrisson"); }
{ put("phoneNumber", "020 1234 8879"); }
});
otherContacts.push(new HashMap() {
{ put("birthday", "July 7, 1940"); }
{ put("firstName", "Ringo"); }
{ put("lastName", "Starr"); }
{ put("phoneNumber", "020 1234 4561"); }
});
let otherContacts : WCWebcom = adbk.child("other_contacts")!
otherContacts.push( [ "birthday" : "February 25, 1943" ,
"firstName": "George",
"lastName" : "Harrisson",
"phoneNumber" : "020 1234 8879"] as NSObject)
otherContacts.push( [ "birthday" : "July 7, 1940" ,
"firstName": "Ringo",
"lastName" : "Starr",
"phoneNumber" : "020 1234 4561"] as NSObject)
As a result, our database content now looks like (note the unique IDs generated by the push() method):
{
"other_contacts": {
"-JtJIbH-AMSjUj-e-QAR": {
"birthday": "February 25, 1943",
"firstName": "George",
"lastName": "Harrisson",
"phoneNumber": "020 1234 8879"
},
"-JtJIbHINoEONq8fxNds": {
"birthday": "July 7, 1940",
"firstName": "Ringo",
"lastName": "Starr",
"phoneNumber": "020 1234 4561"
}
}
}
If you need to get the generated ID, you can use the name() method on the data node returned by the push() method:
// Generate a new contact node
var newContact = otherContacts.push({
firstName: "Yoko",
lastName: "Ono",
phoneNumber: "020 1234 0999"
});
// Get the unique ID of this node
var newContactID = newContact.name();
// Generate a new contact node
Webcom newContact = otherContacts.push(new HashMap() {
{ put("firstName", "Yoko"); }
{ put("lastName", "Ono"); }
{ put("phoneNumber", "020 1234 0999"); }
});
// Get the unique ID of this node
String newContactID = newContact.name();
// Generate a new contact node
let newContact = otherContacts?.push([
"firstName": "Yoko",
"lastName" : "Ono",
"phoneNumber" : "020 1234 0999"] as NSObject)
// Get the unique ID of this node
let newContactID = newContact!.name