Skip to content

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":

opresult-output-input.zoom80

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 the objectId property assigned by the server. You need to get the objectId 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.
{
  "___ref" : true,
  "opResultId": "someFindObjectsOperation",
  "resultIndex": 2
}
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.
{
  "___ref" : true,
  "opResultId": "someSavingMultipleObjectsOperation",
  "resultIndex": 2
}
collection of strings
Saving multiple objects
property value
Retrieve the value of the objectId property:
{
  "___ref" : true,
  "opResultId": "someSavingMultipleObjectsOperation",
  "propName": "objectId"
}
object
Saving single object, Updating single object
property value
Retrieve the value of the name property for the 3rd object in the collection:
{
  "___ref" : true,
  "opResultId": "someFindObjectsOperation",
  "resultIndex" : 3,
  "propName": "name"
}
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":

opresultvaluereference-output-input.zoom80

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:

order-table

OrderItem table schema:

orderitem-table

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:

  1. Save an object in the Person table
  2. Gets the objectId value of the saved person object
  3. Stores the objectId in the CreationLog 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:

person-table-schema

CreationLog table schema:

creationlog-table

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
         }
      }
   }
}