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 thebatchId
field is a user-defined string that can be used to identify the created reference in the response. -
A reference has a
source
andtarget
fields used to identify the source and target components of the reference being created. The value of thesource
andtarget
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:
- If NO reference is matched then a new reference will be created.
- If EXACTLY ONE reference is matched then that reference will be updated.
- 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:
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.
-
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 Application
s, 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.
-
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.
-
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:
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}}
]
}
}
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.
- Every created reference is a dependency.
- Every updated reference is a dependency.
- Every upserted reference is a dependency.