Operation Result¶
One of the most powerful elements of the Backendless Transactions API is the ability to use the result of an operation in other subsequent operation within the same transaction. This is made possible by a "protocol" that all transactional operations follow: every operation can have a unique identifier. The identifier can be used in another operation to reference the result from the operation where it was used. This allows for a "chaining effect" where data comes out of one operation and then fed into another.
Consider the example below. The example saves a new object in the database and then establishes a relationship between the created object and objects in another table. As you can see, the operation to save the object in the database assigns a unique id to the operation with the opResultId
property which then is used in the subsequent operation to establish a relationship between the object and its children:
{
"operations": [
{
"operationType": "CREATE",
"table": "Person",
"opResultId": "createJoe",
"payload": {
"name": "Joe",
"age": 20
}
},
{
"operationType": "SET_RELATION",
"table": "Person",
"payload": {
"parentObject": {
"___ref": true,
"opResultId": "createJoe",
"propName": "objectId"
},
"relationColumn": "visitedCountries",
"conditional": "name = 'China'"
}
}
]
}
The most important in the example above is how the result from the "CREATE"
operation is used in the "SET_RELATION"
operation.
The general syntax for referencing the result of an operation is:
{
"___ref" : true,
"opResultId": "VALUE",
"resultIndex": NUMBER,
"propName" : "VALUE"
}
where:
Argument | Description |
---|---|
"___ref" |
A mandatory property. The value must be set to "true" . It indicates to Backendless that this is a reference to a result from another operation in the same transaction. |
"opResultId" |
Must contain an opResultId identifier of another operation whose result should be used as the input argument. See the example above for the reference. |
"resultIndex" |
An optional property. Must contain a numeric (integer) value. If the result of the operation referenced by "opResultId" is a collection, this value identifies an element from the collection. The referenced element is used as an argument, unless the "propName" is also set. See the "A Value in the Result" section below for more details. |
"propName" |
References a property within the result. If the result identified by "opResultId" is a single object, then the property identified by "propName" is referenced. Otherwise, if the result identified by "opResultId" is a collection, the "resultIndex" must be used to reduce the collection to a single object first and then "propName" is applied. See the "A Value in the Result" section below for more details. |
It is important to understand that different operations have different return types. For instance, the Retrieving objects operation result is a collection of objects, while the Saving single object result is the created object. As a result, when another operation references the result from a previous one, the actual referenced result will vary depending on what the operation with the opResultId
is. The table below summarizes the return values for all supported transaction operations in Backendless:
Operation |
Operationname |
Result represented by opResultId when referenced in another operation |
---|---|---|
Retrieving objects |
find |
Collection of complete objects returned by the query |
Saving single object |
create |
Object saved on the database (with objectId assigned) |
Saving multiple objects |
bulkCreate |
Collection of objectId values |
Updating single object |
update |
Object updated in the database |
Updating multiple objects |
bulkUpdate |
Number of objects updated in the database |
Deleting single object |
delete |
Timestamp (as a number) when the object was deleted |
Deleting multiple objects |
bulkDelete |
Number of objects deleted in the database |
Setting a relation |
setRelation |
Number of child objects set in the relation to the parent |
Adding to a relation |
addToRelation |
Number of child objects added in the relation to the parent |
Deleting from a relation |
deleteRelation |
Number of child objects disconnected/removed from the relation with the parent |
Using opResultId as Input¶
Most operations can accept opResultId
as an argument. This is the how the "chaining effect" described above is accomplished. It is very important to understand that the value represented by opResultId
must be acceptable as an argument by the operation where it is being passed to. For example, the Deleting a single object operation can accept opResultId
. However, it cannot be any opResultId
, it must be a result which represents a single object. The diagram below illustrates where the output/result of an operation can be used as the input in another one. An arrow going out from a block represents opResultId
referenced by that operation. As you can see some arrows have labels on them indicating the role opResultId
plays as the argument. This is the specifics of the relation management operations - they can accept opResultId
in two different roles - "as the parent" and "as children":
A Value In a Result¶
Consider the following scenarios:
- In your transaction you run an operation to retrieve data from the database. The operation returns a collection of objects (represented by
opResultId
), however, you need to get the second object from the collection and update it in a subsequent operation. - In your transaction you save an object in the database. The operation returns the created object (represented by
opResultId
) which has theobjectId
property assigned by the server. You need to get theobjectId
value and store it in the database.
As you can see from these scenarios, there is a need to reference a value represented by opResultId
. In the first case the extracted value is an object from the collection. In the second one, it is a string value of the objectId
property. To accommodate these and many similar scenarios, a value within a result can be referenced using the following format:
{
"___ref" : true,
"opResultId": "VALUE",
"resultIndex": NUMBER,
"propName" : "VALUE"
}
To reference a value in a result, you can use a combination of the resultIndex
and the propName
parameters. The table below describes possible combinations:
a value in a result is: |
how to reference the value in a result: |
result from the referenced operation is: |
referenced operation |
---|---|---|---|
object |
Retrieve 3rd object from the returned result. Indexes are zero-based, that's why index of 2 references the 3rd object. |
||
|
|||
collection of objects |
Retrieving objects |
||
string |
Retrieve 3rd object from the returned result. Indexes are zero-based, that's why index of 2 references the 3rd object. |
||
|
|||
collection of strings |
Saving multiple objects |
||
property value |
Retrieve the value of the objectId property: |
||
|
|||
object |
Saving single object, Updating single object |
||
property value |
Retrieve the value of the name property for the 3rd object in the collection: |
||
|
|||
collection of objects |
Retrieving objects |
The diagram below illustrates where in subsequent operations a value from an operation result can be as an input. An arrow indicates that it is possible to obtain a value from an operation result returned by the operation represented by the block where the arrow starts. An arrow coming into a block indicates that the block can accept a value from an operation result as an argument. As you can see some arrows have labels on them indicating the role plays as the argument. This is the specifics of the relation management operations - they can accept a value from an operation result in two different roles - "as the parent" and "as children":
Examples¶
Parent, Child and Relation¶
This example demonstrates how a single transaction can be used to accomplish the following:
- Save the parent object in the database
- Save the child objects in the database
- Create a relation between the parent and the children
It is important that the schema for both tables used in the example is created before the transaction is executed. This is what the schema looks like:
Order table schema:
OrderItem table schema:
Request:
{
"operations": [
{
"operationType": "CREATE",
"table": "Order",
"opResultId": "createOrder",
"payload": {
"orderId": "031820-CV1",
"amount": 189.20
}
},
{
"operationType": "CREATE_BULK",
"table": "OrderItem",
"opResultId": "createOrderItems",
"payload": [
{
"name":"Paper Towels",
"quantity":10
},
{
"name":"Bathroom Tissue",
"quantity":20
}
]
},
{
"operationType": "SET_RELATION",
"table": "Order",
"payload": {
"parentObject": {
"___ref": true,
"opResultId": "createOrder",
"propName":"objectId"
},
"relationColumn": "orderDetails",
"unconditional": {
"___ref": true,
"opResultId": "createOrderItems"
}
}
}
]
}
Response:
{
"success":true,
"error":null,
"results":{
"createOrder":{
"type":"CREATE",
"result":{
"orderId":"031820-CV1",
"amount":189.2,
"___class":"Order",
"objectId":"F32E20DC-924A-AEA9-FF9D-C9FFBC37FD00",
"created":1585961922000,
"updated":null,
"ownerId":null,
"orderStatus":null,
"deliveryDate":null
}
},
"createOrderItems":{
"type":"CREATE_BULK",
"result":[
"016210BA-116B-7B08-FFCD-181C6CC63100",
"B3DA11C9-6A1F-9A48-FFCE-4B7C4A7AFF00"
]
},
"set_relationOrder1":{
"type":"SET_RELATION",
"result":2
}
}
}
Get a Property Reference from Operation Result¶
This example demonstrates how to store an object in a transaction and then access the value of a property of the saved object (its objectId
) to store it in another data table. In other words, the example does the following:
- Save an object in the
Person
table - Gets the
objectId
value of the saved person object - Stores the
objectId
in theCreationLog
table
It is important that the schema for both tables used in the example is created before the transaction is executed. This is what the schema looks like:
Person table schema:
CreationLog table schema:
Request:
{
"operations": [
{
"operationType": "CREATE",
"table": "Person",
"opResultId": "createBatman",
"payload": {
"name": "Batman",
"age": 36
}
},
{
"operationType": "CREATE",
"table": "CreationLog",
"payload": {
"objectCreated": {
"___ref":true,
"opResultId":"createBatman",
"propName":"objectId"
},
"tableName":"Person"
}
}
]
}
Response:
{
"success":true,
"error":null,
"results":{
"createBatman":{
"type":"CREATE",
"result":{
"name":"Batman",
"age":36,
"___class":"Person",
"objectId":"8FB6483E-40C8-F3A6-FFFB-E8A096DBE100",
"created":1585964547000,
"updated":null,
"ownerId":null
}
},
"createCreationLog1":{
"type":"CREATE",
"result":{
"objectCreated":"8FB6483E-40C8-F3A6-FFFB-E8A096DBE100",
"tableName":"Person",
"___class":"CreationLog",
"objectId":"79305064-5B8B-6CCA-FFD0-EB3FB4CEC900",
"created":1585964547000,
"updated":null,
"ownerId":null
}
}
}
}