Editing (endpoint name Edit
)¶
The Edit service provides mutations to create new records, and modify or delete existing records.
Creating new records¶
The add
mutation is used to create new records. To create a record three bits of information are needed: the table the record will reside in, the type
for the new record, and an idno
(a unique user-provided identifier) value. Other data elements (or “bundles”) can be set by listing them in the bundles
parameter of the query. For example:
mutation {
add(
table: "ca_objects",
idno: "test.101",
type: "artifact",
bundles: [
{ name: "preferred_labels", value: "My first record"},
{ name: "description", value: "This is a new record!"},
{ name: "date", value: "April 3 1984"}
]
) {
id,
table,
identifier,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
This mutation will create a new artifact object record with the provided values for idno, title (aka. preferred label), description and date. Note that that format for the idno
value, valid values for type
and available bundles are system-specific. The values used here are examples.
The bundles
parameter takes a list of bundle value specifications. Each specification requires, at a minimum, a bundle name
and value
to set. For bundles that repeat, specifications with the same bundle name may be set. For example, to set multiple dates on an object (assuming the schema is configured to allow repeating dates):
mutation {
add(
table: "ca_objects",
idno: "test.101",
type: "artifact",
bundles: [
{ name: "preferred_labels", value: "My first record"},
{ name: "description", value: "This is a new record!"},
{ name: "date", value: "April 3 1984"},
{ name: "date", value: "June 8 1984"},
{ name: "date", value: "July 26 1984"}
]
) {
id,
table,
identifier,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
If your system supports multiple cataloguing locales, the locale for each bundle value may be specified using locale
and an ISO code:
{ name: "description", value: "Hier ist ein neuer Rekord", locale: "de_DE" },
If you omit the locale value for a bundle, the system default locale is used.
For container bundles – fields that contain sub-fields, set values
for the bundle specifier with a list of sub-field specifiers. For example:
mutation {
add(
table: "ca_objects",
idno: "test.101",
type: "artifact",
bundles: [
{ name: "preferred_labels", value: "My first record"},
{ name: "description", value: "This is a new record!"},
{ name: "address", values: [
{ name: "address1", value: "1000 Surf Avenue" },
{ name: "city", value: "Brooklyn" },
{ name: "state", value: "NY" },
{ name: "postal_code", value: "11224" },
{ name: "country", value: "USA" }
]}
]
) {
id,
table,
identifier,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
Similarly, for preferred and non-preferred labels that take multiple sub-values, such as entities, values
may be set on the bundle to specific sub-field values:
mutation {
add(
table: "ca_entities",
idno: "E.1",
type: "individual",
bundles: [
{ name: "preferred_labels", values: [
{ name: "forename", value: "David" },
{ name: "surname", value: "Lowery" },
{ name: "middlename", value: "Alan" },
{ name: "prefix", value: "Mr" }
]},
{ name: "biography", value: "He was born in Brooklyn in 1914... etc etc"},
{ name: "lifedates", value: "February 13, 1914 - March 6, 1981"}
]
) {
id,
table,
idno,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
For non-preferred labels, which take an option label type value, you may also pass type
in the bundle specification. If it is omitted the default type will be used.
Note that all bundles are assumed to be bound to the table to which you are adding the record. To manage relationships between records use the addRelationship
, editRelationship
, deleteRelationship
and deleteAllRelationships
mutations described below. You may also create relationships within the add
mutation using the relationships
parameter described below.
The add
mutation can return the internal CollectiveAccess id
value for the newly created record, the table
of the record (always the same as the table parameter passed in the mutation), the idno value (which may be calculated using a server-side policy and differ from the passed value) and a list of errors, warnings and informational messages related to the add operation. Errors indicate failures and include an error code, the idno of the affected record, a descriptive message and the name of the bundle the error affects. Non-bundle-specific errors will have a bundle code of GENERAL
. Warnings indicate possible error conditions and issues, and are purely advisory. Informational messages (info
) provide details about processing stages of the mutation, including how existing records may or may not have been matched, and if related records may have been created. Both warnings
and info
messages have a simliar structure to error
.
Multiple adds and hierarchies¶
Multiple records may be created in single request using the records
parameter. Each record includes an idno
, type
and bundles
list. The insertMode
parameter controls how records are created. Setting insertMode
to FLAT (the default) will create individual records. Setting insertMode
to HIERARCHICAL will arrange the newly created records in a hierarchy, with the first listed record as the hierarchical root. This example will create three levels in the storage location hierarchy:
mutation {
add(
table: "ca_storage_locations",
insertMode: "HIERARCHICAL",
existingRecordPolicy:"IGNORE",
ignoreType: true,
records:[{
idno: "s.1",
type: "building",
bundles: [
{ name: "preferred_labels", value: "Hibbens Hall", replace: true}
]
},{
idno: "f.1",
type: "floor",
bundles: [
{ name: "preferred_labels", value: "Floor 1"}
]
},{
idno: "r.123",
type: "room",
bundles: [
{ name: "preferred_labels", value: "Room 123"}
]
} ]
) {
id,
table,
idno,
changed,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
The existingRecordPolicy
parameter controls behavior when a record with the specified idno value (or other specified criteria, as described in the next section) is already present.
Value |
Description |
---|---|
IGNORE |
Ignore existing records and attempt to create a new record. |
REPLACE |
Delete the existing record and insert a new record. |
MERGE |
Merge bundles into existing record. Essentially the same as editing the existing record. |
SKIP |
Skip add if record with idno already exists. |
If you do not set and existing record policy, SKIP is assumed.
By default, existing records must match on idno, type and parent (when using HIERARCHICAL
insert mode). The type matching requirement can be relaxed by passing the ignoreType
option as in the previous example. The parent matching requirement when in HIERARCHICAL
insert mode can be relaxed by passing the ignoreParent
option.
Adding relationships to a new record¶
Relationships may be established between an added record and existing records using the relationships
list parameter. Each item in the relationships list contains keys for target
(the table to relate to) and relationshipType
(a valid relationship type code for the relationship to be created). The record to relate to must be specified using one of the following: targetId
(the database ID of the record to relate to), targetIdno
(the idno of the related record), or targetIdentifer
(the idno or database ID). You may also set interstitial data on the relationship by passing an optional bundles
parameter within a relationships
item. For example:
mutation {
add(
table: "ca_objects",
idno: "2020.11.1",
type: "artifact",
bundles: [
{ name: "preferred_labels", value: "Thimble Folk"},
{ name: "description", value: "Highly collectible felt dolls."}
],
replaceRelationships: false,
relationships: [
{
target:"ca_entities",
targetIdentifier: "E.100",
relationshipType:"donor",
bundles: [
{ "effective_date": "1961 - 1965" }
]
}
]
) {
id,
table,
idno,
changed,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
Any number of relationships may be added to a record in this way. If the add
mutation is for a record that already exists in the database, relationships will be added to the existing record with relationships matching existing ones skipped. To force the relationships on existing records to conform those specified in the mutation set the replaceRelationships
parameter to true (the default is false). This will cause all existing relationships to be removed before the relationships specified in the mutation are added.
relationships
and replaceRelationships
may be specified at the top level of the mutation when the mutation is for a single new record (as shown above). For multiple adds, the parameters must be specified for each record in the records
list.
Matching using other fields¶
Matching of existing records is typically done with idno
values, but other data may be used as well. To toggle between matching on idno
or preferred label use the matchOn
parameter set to a list containing one or both of the values “idno” or “preferred_labels” in the order of precedence. Setting matchOn
to
matchOn: ["preferred_labels", "idno"]
will result in matching on preferred labels, falling back to idno if there are no label matches. Setting a single value will result in matching on only the specified field.
Arbitrary matching criteria may be specified using the match
parameter. match
offers two sub-parameters: search`
matches records using a query string; criteria
matches records using field-level search criteria. The two sub-parameters are analogous to the search
and find
queries in the search endpoint, taking identical input and employing the same methods to locate matches.
match
and matchOn`
may be used in conjunction with existingRecordPolicy
to implement useful data migration patterns that might otherwise require several separate queries and mutations. One common data migration pattern occurs when importing a data set that includes references to related records (a set of artworks with related artists, for example). In this case, one would process each object record in turn, creating related entity records for artists that don’t already exist, and then establishing object-artist relationships. Without match
or matchOn
the process would require these steps:
Create the object
Perform a
search
query for each artist related to the objectCreate entity records for all artists that did not return a match
Create relationships between the entities and newly created object
By using an add
mutation with relationships
set to the relevant object, match
> criteria
set to the artist’s name and an existingRecordPolicy
of MERGE
, steps 2-4 can be consolidated into a single mutation that finds matching artist records based upon name, creates a new record for an artist if there are no matches, and then creates an object-artist relationship between the matched or newly created artist record. The mutation might look like this, if you wanted to match both name and lifedates:
mutation {
add(
table: "ca_entities",
idno: "E.%",
type: "individual",
bundles: [
{ name: "preferred_labels", values: [
{ name: "forename", value: "David" },
{ name: "surname", value: "Lowery" },
{ name: "middlename", value: "Alan" },
{ name: "prefix", value: "Mr" }
]},
{ name: "biography", value: "He was born in Brooklyn in 1914... etc etc"},
{ name: "lifedates", value: "February 13, 1914 - March 6, 1981"}
],
existingRecordPolicy: "MERGE",
match: {
find: [
{
name: "ca_entities.preferred_labels.surname",
operator: EQ,
value: "Lowery"
},
{
name: "ca_entities.preferred_labels.forename",
operator: EQ,
value: "David"
},
{
name: "lifedates",
operator: EQ,
value: "February 13, 1914 - March 6, 1981"
}
]
},
relationships: [
{
target:"ca_objects",
targetIdentifier: "2021.004.001",
relationshipType:"donor"
}
]
) {
id,
table,
idno,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
If only a name match is required, a somewhat simpler mutation using matchOn
might look like this;
mutation {
add(
table: "ca_entities",
idno: "E.%",
type: "individual",
bundles: [
{ name: "preferred_labels", values: [
{ name: "forename", value: "David" },
{ name: "surname", value: "Lowery" },
{ name: "middlename", value: "Alan" },
{ name: "prefix", value: "Mr" }
]},
{ name: "biography", value: "He was born in Brooklyn in 1914... etc etc"},
{ name: "lifedates", value: "February 13, 1914 - March 6, 1981"}
],
existingRecordPolicy: "MERGE",
matchOn: ["preferred_labels"],
relationships: [
{
target:"ca_objects",
targetIdentifier: "2021.004.001",
relationshipType:"donor"
}
]
) {
id,
table,
idno,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
Important
In an add
mutation, when a search
, find
matches more than one record the first record found is considered the existing record. All other matches are discarded. For predictable results use criteria that will return unique matches. matchOn
only matches using fields that are typically unique (idno and preferred labels), but will exhibit the same behavior should those fields include non-unique values.
Editing records¶
To edit an existing record, the edit
mutation is used with the target record specified by table
and identifier
parameters. The identifier
parameter may be either an numeric internal CollectiveAccess ID value or the idno
value of a record. Note that idno
values are not guaranteed to be unique (although they typically are). If more than one record matches the identifier, the first match will be edited and additional matches ignored. If the supplied identifier
is numeric it will be matched first as an internal ID, and subsequently as an idno
if no internal ID is found. In cases where idno
values solely contain digits, mismatches may occur. To force matching on internal ID or idno
only use the id
and idno
parameters respectively, rather than identifier
.
Edited values are specified in the bundles
parameter, similar to the format used for adding with a few additions. By default each listed bundle will be appended to the record. For bundles supporting repeating values, this means the addition of values. For fields that limited or not repeatability, edits will fail once the limit is reached. To replace a value rather than append to it, a replace
value set to true
may be set in the bundle specification. If a value exists it will be replaced by the new value; if no value exists yet, the new value will be added.
To target a specific value in a bundle with multiple repeating values a value id
may be set in the bundle specifier. These id
values can be returned alongside their values in Item
service endpoint responses (described above)
To delete a value from a record set a delete
value to true
in the bundle specifier. If id
is also specified the specific value will be removed. If id
is omitted all values will be removed.
An edit
mutation that changes the idno
, replaces the description and removes all non-preferred labels:
mutation {
edit(
table: "ca_objects",
identifier: "TEST.1",
bundles: [
{name:"idno", value: "test.101"},
{ name:"nonpreferred_labels", delete: true },
{ name: "description", value: "This is a new description", replace: true }
]
) {
id,
table,
idno,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
Note that the response format is identical to that used for add
.
Relationships may be specified for edits in the same manner they are for the add
mutation.
Multiple edits¶
Multiple records may be edited in single request using the records
parameter. Each record includes an identifier
(or id
or idno
), type
and bundles
list. This example will edit the preferred labels of three objects in a single request:
mutation {
edit(
table: "ca_objects",
records:[{
identifier: "Test.400",
bundles: [
{ name: "preferred_labels", value: "My new title", replace: true}
]
},{
identifier: "Test.401",
bundles: [
{ name: "preferred_labels", value: "Another new title", replace: true}
]
},{
identifier: "Test.450",
bundles: [
{ name: "preferred_labels", value: "A third new title", replace: true}
]
} ]
) {
id,
table,
idno,
changed,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
Deleting records¶
To delete a record, pass the table and an identifier (CollectiveAccess ID value or idno
value):
mutation {
delete(
table: "ca_objects",
identifier: "test.101"
) {
id,
table,
identifier,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
The response will be in the same format as that used for add
and edit
mutations, but id
and identifier
will always be set to null.
As with edits, if the supplied identifier
is numeric it will be matched first as an internal ID, and subsequently as an idno
if no internal ID is found. In cases where idno
values solely contain digits, mismatches may occur. To force matching on internal ID or idno
only use the id
and idno
parameters respectively, rather than identifier
.
To delete multiple records with in single request, pass a list of identifiers using the identifiers
parameter. To force matching on internal ID or idno
use the ids
and idnos
parameters respectively.
Truncating tables¶
When developing or debugging a data import process it is often useful to quickly delete some or all of the records in a table. The truncate
mutation can remove all records in a table, or selected records based upon last modification date and/or record types.
This mutation would delete all entities of type ind
modified after July 21 2021 at 5pm:
The fast
option will remove records as quickly as possible by skipping update of the change log and search index. When truncating tables with large numbers of records, this can result in significant time savings. For development systems, the lack of consistent change logging and indexing for deleted records is usually not an issue. The fast
option should not be used in production systems.
Important
Use of this GraphQL service requires authentication with an account having the can_truncate_tables_via_graphql
action privilege.
Specific lists may be truncated using the list
parameter. The date
and types
parameter may be set to restrict which items in the list are removed. If list
is set table
is ignored:
mutation {
truncate(
list:"chemical_deterioration", fast: true
) {
id
table,
idno,
changed,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
Creating relationships¶
mutation {
addRelationship(
subject: "ca_objects",
target: "ca_entities",
subjectIdentifier: "test.1",
targetIdentifier:"51",
relationshipType: "creator"
) {
id,
idno,
table,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
Returns:
{
"ok": true,
"data": {
"addRelationship": {
"id": 1,
"idno": null,
"table": "ca_objects_x_entities",
"errors": [],
"warnings": [],
"idno": []
}
}
}
If the supplied subjectIdentifier
or targetIdentifier
values are numeric they will be matched first as internal IDs, and subsequently as idno
if no internal ID is found. In cases where idno
values solely contain digits, mismatches may occur. To force matching on internal ID or idno
only use the subjectId
(or targetId
) and subjectIdno
(or targetIdno
) parameters respectively, rather than subjectIdentifier
and targetIdentifier
.
Editing relationships¶
mutation {
editRelationship(
subject: "ca_objects",
subjectIdentifier: "test.1",
target:"ca_entities",
targetIdentifier: "55",
relationshipType: "creator",
bundles: [
{name: "effective_date", value: "1960"},
{name: "relationship_type", value: "creator"},
{name: "description", value: "hello world???", replace: true}
]) {
id,
table,
idno,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
Deleting relationships¶
mutation {
deleteRelationship(
subject: "ca_objects",
id: 1,
target:"ca_entities"
) {
id,
table,
idno,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}
Deleting all relationships:¶
mutation {
deleteAllRelationships(
subject: "ca_objects",
subjectIdentifier: "test.1",
target:"ca_entities",
relationshipType: "related"
) {
id,
table,
idno,
errors { idno, code, message, bundle },
warnings { idno, code, message, bundle },
info { idno, code, message, bundle }
}
}