A number of MarkLogic Server functions require a query as a parameter. Every now and then, however, you want to call one of those functions without specifying a query. There’s an easy way to handle this: you can use cts:and-query(()) as an empty query. This empty query matches everything, so it’s a simple way of getting all results.
Consider cts:element-query(). Sometimes you want to use the presence of the element, rather than its value. Let’s find the first 100 URIs of documents that have a <title> element. The query parameter is required, so a natural first thought might be to give the empty sequence as the query parameter.
cts:uris('', (), cts:element-query(xs:QName("title"), ()))[1 to 100]
However, if we do this, we get a curious result: the first 100 URIs regardless of whether they have a <title> element or not. Ah, yes, function mapping. By passing the empty sequence, cts:element-query() gets called once for every node in the sequence, which is to say zero times. As such, we end up passing the empty sequence to the query parameter of cts:uris(). So why doesn’t function mapping wipe out our call to cts:uris()? Because the parameter to cts:uris() is specified as “query as cts:query?”. That question mark means that we can pass zero or one values. The cts:element-query() specification has “query as cts:query” — no question mark. So unless you’ve explicitly turned off function mapping, it comes into play.
Let’s revisit that cts:uris() call, but give it a proper empty query this time:
cts:uris('', (), cts:element-query(xs:QName("title"), cts:and-query(())))[1 to 100]
The cts:and-query() with no queries passed in (specified as “queries as cts:queries*”) matches anything. So now our query finds 100 URIs that have <title> elements.
Tags: gotcha, marklogic, xquery
February 16th, 2011 at 5:34 pm
I include the following declaration in all my modules:
declare option xdmp:mapping “false”;
Function mapping has its fans, but it’s too much magic for my simple mind.