I'm trying to come up with a performant way of getting a distinct list of attribute values on an element, given another attribute on that element, and do that across the REST API. I'm using Semaphore with MarkLogic and have documents with elements like:
<META name="fruit" value="apple" />
<META name="fruit" value="banana" />
<META name="fruit" value="cherry" />
<META name="vegetable" value="artichoke" />
<META name="vegetable" value="beet" />
<META name="vegetable" value="carrot" />
So, given "fruit", I'd like to come back with the list (apple, banana, cherry) and given "vegetable", I'd like to come back with (artichoke, beet, carrot).
Lexicons on META/@name
and META/@value
and hitting the /v1/values
endpoint are no problem, but not on sort of the combination. element-attribute-value-co-occurences
and value-tuples
seem to give all possible combinations, so I get fruit/carrot, which I don't want.
Ultimately, I'd like to use this to drive two select lists on a UI, the first containing the distinct name
attributes, then once the user makes a selection, the second would contain the value
attributes appropriate to it.
If you put a TDE in place that pulls the values into a view you can use the Optic API with the /v1/rows endpoint to pull the values. Each row here will align with a Meta pair of name and value. Therefore, you can use the groupBy modifier to get the unique combinations.
TDE:
<tde:template xml:lang="zxx"
xmlns:tde="http://marklogic.com/xdmp/tde">
<tde:description></tde:description>
<tde:context>/es:envelope/es:instance[es:info/es:version = "0.0.1"][Article]</tde:context>
<tde:path-namespaces>
<tde:path-namespace>
<tde:prefix>es</tde:prefix>
<tde:namespace-uri>http://marklogic.com/entity-services</tde:namespace-uri>
</tde:path-namespace>
</tde:path-namespaces>
<tde:templates>
<tde:template>
<tde:context>ancestor::es:envelope/es:headers//es:META</tde:context>
<tde:rows>
<tde:row>
<tde:schema-name>Article</tde:schema-name>
<tde:view-name>Tags</tde:view-name>
<tde:view-layout>sparse</tde:view-layout>
<tde:columns>
<tde:column>
<tde:name>uri</tde:name>
<tde:scalar-type>string</tde:scalar-type>
<tde:val>xdmp:node-uri(.)</tde:val>
<tde:nullable>false</tde:nullable>
<tde:invalid-values>ignore</tde:invalid-values>
</tde:column>
<tde:column>
<tde:name>name</tde:name>
<tde:scalar-type>string</tde:scalar-type>
<tde:val>@name</tde:val>
<tde:nullable>true</tde:nullable>
<tde:invalid-values>ignore</tde:invalid-values>
</tde:column>
<tde:column>
<tde:name>value</tde:name>
<tde:scalar-type>string</tde:scalar-type>
<tde:val>@value</tde:val>
<tde:nullable>true</tde:nullable>
<tde:invalid-values>ignore</tde:invalid-values>
</tde:column>
</tde:columns>
</tde:row>
</tde:rows>
</tde:template>
</tde:templates>
</tde:template>
Optic Query:
'use strict';
const op = require('/MarkLogic/optic');
op.fromView('Article', 'Tags')
.groupBy(op.col('name'), [op.col('value')])
.result();
/v1/rows (https://docs.marklogic.com/REST/POST/v1/rows)
curl --location --request POST 'http://localhost:8011/v1/rows?column-types=header'
--header 'Content-Type: application/vnd.marklogic.querydsl+javascript'
--data-binary '@query.dsl'