Advanced Searching using CQL

Rate this page:

Content properties in the REST API

What are content properties?

Content properties are a form of key-value storage, where the key is associated with a piece of Confluence Content. Content properties are one of the forms of persistence available to you as an add-on developer. Content properties allow to store up to 32 KB of JSON with each piece of content (for example, a page, blog post, or attachment), so, you do not have to use your own data store. If you need to store metadata, for example, about a piece (or pieces) of content, content property is a great way to do it.

Content properties are accessible both by Java and REST APIs.

Query content properties with CQL

You can use CQL to query content properties in your Confluence instance. For example, a plugin can store the number of likes on a page in a content property. You can create an index schema module for that property, and then you can query the values to see how many pieces of content have more than 20 likes.

GET, POST, and DELETE content properties

GET content properties

To retrieve any existing content properties for a piece of content, perform a GET on the endpoint /rest/api/content/{content_ID}/property.

1
2
# Retrieves content properties associated with a piece of content with ID 12345
curl -u admin:admin -X GET "http://localhost:8080/confluence/rest/api/content/12345/property" | python -mjson.tool

POST new content properties

To add content properties to a piece of Confluence content, perform a POST to the same endpoint. The key in your content property can be an arbitrary string (like "myprop"), whereas the value must be a structured JSON.

1
2
3
4
5
6
7
8
9
10
11
12
13
# Stores a JSON document under the key "myprop" against content with ID 12345
curl -i -u admin:admin -X POST -H "Content-Type: application/json" \
-d '{ "key" : "myprop", "value" : 
{
    "id": "507f1f77bcf86cd799439011",
    "editDate": "2000-01-01T11:00:00.000+11:00",
    "description": "If you have any questions please address them to admin@example.com",
    "content": {
        "likes": 5,
        "tags": ["cql", "confluence"]
    }
}
 }' http://localhost:8080/confluence/rest/api/content/12345/property

DELETE content properties

If you need to delete content properties, you can perform a DELETE on the endpoint.

1
2
# Removes JSON document associated with key "myprop from content with ID 12345
curl -i -u admin:admin -X DELETE "http://localhost:8080/confluence/rest/api/content/12345/property/myprop"

Fetch content properties as an expansion when retrieving content

Content properties are available as an expansion on the content resource. This allows content properties to be retrieved in the same REST call as fetching the content itself. This expansion is available from any resource that returns content, including the CQL search resource.

GET content properties as an expansion on content.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# fetch properties at the same time as fetching content, note the expand=metadata.properties.myprop
curl -u admin:admin -X GET 
    "http://localhost:8080/confluence/rest/api/content/12345?expand=metadata.properties.myprop" | python -mjson.tool
{   
    id: "12345",
    type: "page",
    status: "current",
    title: "New in the platform team? Read me first",
    metadata: {
        _expandable: {
            currentuser: "",
            labels: "",
            properties: {
                myprop: {
                    "id": "507f1f77bcf86cd799439011",
                    "editDate": "2000-01-01T11:00:00.000+11:00",
                    "description": "If you have any questions please address them to admin@example.com",
                    "content": {
                            "likes": 5,
                            "tags": ["cql", "confluence"]
                    }
                }
            }
        }
    }
}

CQL search extension

To allow searching of content properties using CQL, you can enable indexing of data stored as content properties by defining an index schema. You can define an exclusive index schema for each content property key; then, whenever a content property is saved, Confluence checks if a schema is defined for its key. If a schema exists, indexable values are extracted from content property values and stored in an index. There can only be one index schema definition for a content property key, so any duplicates are disabled. In the case of offending keys, an appropriate log message is available.

Index schema definition

When defining an index schema for content properties, you need to provide a set of extraction expressions and field type pairs, which are used to retrieve a specific value from a JSON document and transform it into the desired representation. Supported index field types are: string, text, number, and date.

For an example, see the JSON document and its index schema later on this page.

Example of content property value.

1
2
3
4
5
6
7
8
9
{
    "id": "507f1f77bcf86cd799439011",
    "editDate": "2000-01-01T11:00:00.000+11:00",
    "description": "If you have any questions please address them to admin@example.com",
    "content": {
        "likes": 5,
        "tags": ["cql", "confluence"]
    }
}
Extraction definition for a P2 pluginExtracted value
<extract path="id" type="string" />"507f1f77bcf86cd799439011"
<extract path="editDate" type="date" />1st of Jan 2000 00:00:00.000 UTC
<extract path="content.tags" type="string" />An array containing "cql", "confluence"
<extract path="content.likes" type="number" />5

To access an embedded field in a document, use dot notation as shown in the following example. After successful validation, all extracted values are stored inside an index, and you can address them in CQL queries.

Putting it all together, here's a sample index schema definition:

atlassian-plugin.xml

Example of P2 add-on index schema definition

1
2
3
4
5
6
7
8
9
10
11
<content-property-index-schema key="module-key">
    <key property-key="attachments">
        <extract path="id" type="string" />
        <extract path="description" type="text" />
        <extract path="editDate" type="date" />
    </key>
    <key property-key="metadata">
        <extract path="content.tags" type="string" />
        <extract path="content.likes" type="number" />
    </key>
</content-property-index-schema>

Field type doesn't only specify how data is stored in the index, but also determines which CQL operators are available in your query.

Supported index field types

TypeDescriptionSupported CQL operators
stringEntire extracted value will be indexed as a single token, without any filtering. When extraction expression evaluates to a JSON array, each element will be indexed separately. Enables searching for an exact value, e.g. unique identifier.IN, NOT IN, =, !=
textExtracted value will be tokenized before indexing, allowing searching for a particular words.~, !~
numberExtracted number will be indexed as a double value for efficient range filtering and sorting. <, <=, =, !=, >, >=
dateTwo representation are possible, either a String following the ISO 8601 datetime format, or a long value in the Unix time. Enables efficient range filtering and sorting. <, <=, =, !=, >, >=

Querying with CQL

You can address indexed content properties in a CQL query using the content.property field handler. Any content that contains content properties matching the query is returned in the results.

The query syntax is as follows: content.property[<KEY>].<PATH> <OPERATOR> value.

Examples of CQL queries on content properties.

1
2
3
4
content.property[attachments].editDate >= 2001-01-01
content.property[attachments].description ~ "questions"
content.property[metadata].content.tags IN ("cql", "help")
content.property[metadata].content.likes <= 5

Note the dot notation when referencing embedded fields like 'content.likes'.

Legend

SymbolMeaning
KEYThe key of the content properties you search.
PATHThe path to the value you'd like to search in the JSON document (use dot notation for embedded fields).
OPERATOROne of the supported CQL operators for the field type.

Custom content and search body property module descriptors

Content properties which are attached to custom content can also be indexed in the content body field by defining search body property module descriptors which make reference to the custom content type and content property key. This makes custom content searchable by content properties via the CQL 'text' field and also the quick-nav search bar.

For the following examples assume we have two custom content types com.company.product.plugins.pluginName:customType and myCustomType with defined content with IDs 123456789 and 987654321 respectively.

Examples of search body property definitions in atlassian-plugin.xml

1
2
<search-body-property key="moduleKey" content-type="com.company.product.plugins.pluginName:customType" content-property="attachments" />
<search-body-property key="moduleKeyTwo" content-type="myCustomType" content-property="metadata" />

content-type refers to the custom content type.
content-property refers to the content property key to extract the value to be added to the content body field.

Examples of corresponding content properties POST requests for custom content

1
2
3
4
5
# Stores a JSON document under the key "myprop" against content with ID 12345
curl -i -u admin:admin -X POST -H "Content-Type: application/json" \
-d '{ "key" : "attachments", "value" : 
    "This text will be added to the content body field"
 }' http://localhost:8080/confluence/rest/api/content/123456789/property
1
2
3
4
5
6
7
8
9
10
11
# Stores a JSON document under the key "myprop" against content with ID 12345
curl -i -u admin:admin -X POST -H "Content-Type: application/json" \
-d '{ "key" : "metadata", "value" : 
{
    "description": "The whole json value be added to the content body field",
    "content": {
        "likes": 5,
        "tags": ["cql", "confluence"]
    }
}
 }' http://localhost:8080/confluence/rest/api/content/987654321/property
Custom content typeContent idWhat is added to content body field
com.company.product.plugins.pluginName:customType123456789"This text will be added to the content body field"
myCustomType987654321"{ "description": "The whole json value be added to the content body field", "content": { "likes": 5, "tags": ["cql", "confluence"] } }"

Can I use JSON expressions to specify a path?

JSON expressions and extractions that are available when using the index schema are not available as part of the search body property descriptors. In the second content properties example above, the JSON inside the value field will be converted into text and stored in the content body field, even the JSON field names "description" and "content" will be used in indexing for search.

Read also

Rate this page: