Skip to content

Operations on References

Create

Info

If your source and target components are uniquely identifiable within a workspace we recommend that you use the new upsert operation.

  • You can create multiple references by including them in the create list.

  • A reference may have an optional batchId field. The value of the batchId field is a user-defined string that can be used to identify the created reference in the response.

  • A reference has a source and target fields used to identify the source and target components of the reference being created. The value of the source and target fields are the Identifiers of the components.

As an example, the following request will create two references, however we will use different identifiers for their source and target fields.

{
  "aliases": {
    "components": {
      "A": {"name": "A", "rootWorkspace": "c253c98231776d0c8a54879e"},      
    }
  },  
  "components": {
    "create": [
      {
        "batchId": "B",
        "body": {
          "rootWorkspace": "c253c98231776d0c8a54879e",
          "typeId": "p1024822409134",
          "name": "B",
        }
      },
    ]
  },  
  "references": {
    "create": [
      {"body": {"source": "A", "target": "B", "type": 3}},
      {"body": {"source": "A", "target": "6509b612499b5d0001d84921", "type": 7}}
    ]
  }
}

Update

Info

If your source and target components are uniquely identifiable within a workspace we recommend that you use the new upsert operation.

In order to update a reference you must be able to identify it using either its Ardoq OID or an Alias. The body.source and body.target fields may be set to the Identifier of a component.

In the following example we will update one reference using an Ardoq OID and one using an Alias.

{
  "aliases": {
    "components": {
      "A": {"rootWorkspace": "c253c98231776d0c8a54879e", "name": "A"},
      "B": {"rootWorkspace": "c253c98231776d0c8a54879e", "name": "B"},
      "C": {"rootWorkspace": "c253c98231776d0c8a54879e", "name": "C"}
    },
    "references": {
      "A-to-B": {"source": "A", "target": "B", "type": 2}
    }
  },  
  "references": {
    "update": [
      {
        "id": "a0099b8d499b5d0001d84920",
        "ifVersionMatch": "latest",
        "body": { "displayText": "Updated Reference 1", "target": "C" }
      },
      {
        "id": "A-to-B",
        "ifVersionMatch": "latest",
        "body": { "displayText": "Updated Reference 2", "target": "C" }
      }
    ]
  }
}

Upsert

Info

If your source and target components are uniquely identifiable within a workspace we recommend that you use this new upsert operation.

Upserting is the process of creating a new reference if it does not already exist or updating an existing reference if it does. This is particularly useful when writing a custom integration as you can ensure that a reference is created or updated in Ardoq without needing to check if it already exists.

An upsert operation is identical to a create operation with the addition of a uniqueBy list. This list is used to uniquely identify the reference that is being upserted.

The following rules apply:

  1. If NO reference is matched then a new reference will be created.
  2. If EXACTLY ONE reference is matched then that reference will be updated.
  3. If MORE THAN ONE reference is matched then the request will fail.

Warning

To avoid ambiguity, you may NOT include create or update operations on references when upserting references.

The uniqueBy list is a list of strings that correspond to the fields that are used to uniquely identify the component. The order of the strings in the uniqueBy list is not important.

The choice of fields to include in the uniqueBy list will depend on what you are modelling in Ardoq. The following sections will cover the most common ways to identify a reference.

By Custom Field

Gotcha

The string "source.rootWorkspace" must be included in the uniqueBy list when identifying references by custom field, not "rootWorkspace". This is because the rootWorkspace is not included in the body of the reference and is derived from the source field.

In order to identify a reference by a custom field, you must provide the the following strings (in any order) in the uniqueBy list:

["customFields.<custom_field_name>", "source.rootWorkspace"]

Where <custom_field_name> is the name of the custom field that you want to use to uniquely identify the reference.

If a reference with a custom field that matches the value under body.customFields.<custom_field_name> already exists in the workspace that the body.source component belongs to then it will be updated. If no such reference exists then a new reference will be created between the body.source and body.target components.

{
  "references": {
    "upsert": [
      {
        "batchId": "Y",
        "uniqueBy": ["customFields.ref_id", "source.rootWorkspace"],
        "body": {
          "source": "6509b612499b5d0001d84921",
          "target": "4b131856bb51f7fa1aace0db",
          "type": 2,
          "customFields": {"ref_id": "XYZ"}
        }
      }
    ]
  }
}

By Source and Type

Info

The choice between source+type or target+type will depends on the direction of the relationship you are modelling.

Imagine that you are modelling Employees and Locations in Ardoq. You have a reference type called "located at" that you use to model the relationship between an Employee and a Location.

A Location might have multiple employees, but an Employee can only work at one location.

Employee Location
XXXX Oslo
YYYY London
ZZZZ Oslo

In the example above there are two employees located in Oslo, however we would consider it an error if employee XXXX was located at both Oslo and London. This can be viewed in terms of source, target and type in the following table:

Source Type Target
XXXX located at Oslo
YYYY located at London
ZZZZ located at Oslo

We can model this constraint by specifying the source and type as unique.

["source", "type"]
  • If the Employee is not "located at" a Location, then we will create a new reference from the source (Employee) to the target (Location).

  • If the Employee is already "located at" EXACTLY ONE Location, then we will update the value of the references target (Location) to ensure that the source Employee works at the correct location as well as setting any custom fields.

  • If the Employee is already "located at" MORE THAN ONE Location, then the request will fail as the constraint has been violated.

{
  "components": {
    "upsert": [
      {
        "batchId": "employee-XXXX",
        "uniqueBy": ["customFields.employee_id", "rootWorkspace"],
        "body": {
          "rootWorkspace": "c253c98231776d0c8a54879e",
          "typeId": "p1024822409134",
          "name": "Some Employee Name",
          "customFields": { "employee_id": "XXXX" }
        }
      },
      {
        "batchId": "Oslo",
        "uniqueBy": ["name", "rootWorkspace"],        
        "body": {
          "rootWorkspace": "c253c98231776d0c8a54879e",
          "typeId": "p2874929873892",
          "name": "Oslo Office"          
        }
      }
    ]
  },
  "references": {
    "upsert": [
      {
        "uniqueBy": ["source", "type"],
        "body": {
          "source": "employee-XXXX",
          "target": "Oslo",          
          "type": 99
        }
      }
    ]
  }  
}

By Target and Type

Info

The choice between source+type or target+type will depends on the direction of the relationship you are modelling.

Imagine that you are modelling Application ownership in Ardoq. You have a reference type called "owns" that you use to model the relationship between an Employee and an Application.

An Employee may own multiple Applications, but an Application can only have one owner.

Employee Application
XXXX Ardoq
YYYY Some App
XXXX Other App

In the example above there are two applications owned by employee XXXX, however we would consider it an error if Some App was owned by multiple Employees. This can be viewed in terms of source, target and type in the following table:

Source Type Target
XXXX owns Ardoq
YYYY owns Some App
XXXX owns Other App

We can model this constraint by specifying the target and type as unique.

["target", "type"]
  • If the Application is not "owned" by an Employee, then we will create a new reference from the Employee to the Application.

  • If the Application is already "owned" by EXACTLY ONE Employee, then we will update the value of the references source (Employee) to ensure that the target Application is owned by the correct Employee as well as setting any custom fields.

  • If the Application is already "owned" by MORE THAN ONE Employee, then the request will fail as the constraint has been violated.

{
  "components": {
    "upsert": [
      {
        "batchId": "employee-XXXX",
        "uniqueBy": ["customFields.employee_id", "rootWorkspace"],
        "body": {
          "rootWorkspace": "c253c98231776d0c8a54879e",
          "typeId": "p1024822409134",
          "name": "Some Employee Name",
          "customFields": { "employee_id": "XXXX" }
        }
      },
      {
        "batchId": "Ardoq",
        "uniqueBy": ["name", "rootWorkspace"],        
        "body": {
          "rootWorkspace": "c253c98231776d0c8a54879e",
          "typeId": "p2874929873892",
          "name": "Ardoq"
        }
      }
    ]
  },
  "references": {
    "upsert": [
      {
        "uniqueBy": ["source", "type"],
        "body": {
          "source": "employee-XXXX",
          "target": "Ardoq",          
          "type": 66
        }
      }
    ]
  }  
}

By Source, Target and Type

Sometimes you may need to ensure that there is only one reference of a certain type between two components. Imagine that you were modelling "blocks"

Task Blocked Task
Feature A Feature B
Feature A Feature C
Feature B Feature C

In this case it would be an error if the row Feature A, Feature B was duplicated.

This can be viewed in terms of source, target and type in the following table:

Source Type Source
Feature A blocks Feature B
Feature A blocks Feature C
Feature B blocks Feature C

We can model this constraint by specifying the source, target and type as unique.

["source", "target", "type"]
  • If the Task does not block the Blocked Task, then we will create a new "blocks" reference from the Task to the Blocked Task.

  • If the Task already "blocks" the Blocked Task, then we will update the reference. For example, setting any custom fields.

  • If the Task already "blocks" the same Task MORE THAN ONCE, then the request will fail as the constraint has been violated.

Delete

In order to delete a reference you must be able to first identify it.

By Ardoq OID

If you know the Ardoq OID of the reference that you wish to delete, then you can include it directly. For example, in order to delete a reference with the ID "a0099b8d499b5d0001d84920" you would include the following:

{
  "references": {
    "delete": [
      {"id": "a0099b8d499b5d0001d84920"}
    ]
  }
}

By Alias

If you can uniquely identify the reference using a combination of fields, then you can use an alias in place of an id. In this example, we know that there is exactly one reference with the provided source, target and type:

{
  "aliases": {
    "components": {
      "A": {"name": "A", "rootWorkspace": "c253c98231776d0c8a54879e"},
      "B": {"name": "B", "rootWorkspace": "c253c98231776d0c8a54879e"}      
    },
    "references": {
      "A->B": {"source": "A", "target": "B", "type": 2}
    }
  },
  "references": {
    "delete": [
      {"id": "A->B"}
    ]
  }
}

By Match (Smart Delete)

Deleting by match is the most powerful way of deleting references from Ardoq.

It can be combined with upsert operations to ensure that references are deleted if they are no longer needed.

A match is an object with a single key "match" whose value is identical to that of an alias . However, unlike aliases and the uniqueBy of an upsert a match object is expected to correspond to zero or more references. Thus, in the following example ANY reference with the source component identified by the alias "A" and with type 2 will be deleted from the workspace "c253c98231776d0c8a54879e"; be that zero, one or more.

{
  "aliases": {
    "components": {
      "A": {"name": "A", "rootWorkspace": "c253c98231776d0c8a54879e"}      
    }    
  },
  "references": {
    "delete": [
      {"match": {"source": "A", "type": 2}}
    ]
  }
}
This differs from aliases that must match exactly one entity.

The following table covers the combinations of fields that can be used to identify a reference in a match object.

rootWorkspace targetWorkspace type source target customFields.<X>

Dependencies

One important aspect of deleting by match is that references that are dependencies of a Batch request WILL NOT be deleted. This means that you can not delete references that you are creating/updating/upserting at the same time.