MarkLogic XQUERY - How can I search documents by collections and date?

I'm starting with MarkLogic, and I would like to know how can I get documents json from Marklogic with xquery. I've got the next xquery:

xquery version "1.0-ml";
(: Parameter of Input :)
declare variable $ruc as xs:string external;
declare variable $startDate as xs:string external;
declare variable $endDate as xs:string external;

declare function local:findDocumentsByColletion($ruc as xs:string) {
  for $i in cts:search(fn:doc(),
    cts:and-query((cts:collection-query("TRANSACTION"), 
                 cts:collection-query($ruc))))
  return $i
};
for $doc in local:findDocumentsByColletion ($ruc)
return $doc

There is only get documents by collections but I don't know how search by dates with startDate and endDate as parameters for search documents.

I've tried with this example https://docs.marklogic.com/guide/search-dev/rangequery, but it's different because search is just on one document xml.

My function for search by date would be so:

declare function local:findDocumentsByDate($startDate as xs:string, $endDate as xs:string) {
  for $doc in local:findDocumentsByColletion ($ruc)
    cts:search($doc/Authorization,
    cts:element-range-query(xs:QName("Timestamp"), ">=", xs:date($startDate)),
    cts:element-range-query(xs:QName("Timestamp"), "<=", xs:date($endDate)))
  return $doc
}

But it doesn't work:

[1.0-ml] XDMP-UNEXPECTED: (err:XPST0003) Unexpected token syntax error, unexpected QName_
Stack Trace

At line 18 column 4:
In xdmp:eval("&#10;xquery version &quot;1.0-ml&quot;;&#10;(: Parameter of Inpu...", (), <options xmlns="xdmp:eval"><database>4000066727531963679</database>...</options>)
16. declare function local:findDocumentsByDate($startDate as xs:string, $endDate as xs:string) {
17. for $doc in local:findDocumentsByColletion ($ruc)
18. cts:search($doc/Authorization,
19. cts:element-range-query(xs:QName("Timestamp"), ">=", xs:date($startDate)),
20. cts:element-range-query(xs:QName("Timestamp"), "<=", xs:date($endDate)))

Any suggestions?

Upvotes: 1

Views: 1137

Answers (2)

grtjn
grtjn

Reputation: 20414

I like the idea of creating reusable functions that can be composed to find the result you are searching for. However, you cannot wrap searches in the way you do, nor would that be performant.

I'd recommend creating functions that provide portions of the total query, instead of doing multiple searches. You compose those into a large query, and execute that with just one cts:search. Something like:

declare function local:findDocumentsByColletion($ruc as xs:string) {
  cts:and-query((
    cts:collection-query("TRANSACTION"), 
    cts:collection-query($ruc)
  ))
};

declare function local:findDocumentsByDate($startDate as xs:string, $endDate as xs:string) {
  cts:and-query((
    cts:element-range-query(xs:QName("Timestamp"), ">=", xs:date($startDate)),
    cts:element-range-query(xs:QName("Timestamp"), "<=", xs:date($endDate))
  ))
};

cts:search(collection()/Authorization, cts:and-query((
  local:findDocumentsByCollection($ruc),
  local:findDocumentsByDate($startDate, $endDate)
)))

HTH!

Upvotes: 0

mholstege
mholstege

Reputation: 4912

You are almost there. Since you want both range conditions to hold, you need to wrap them in a cts:and-query:

cts:search($doc/Authorization,
   cts:and-query((
    cts:element-range-query(xs:QName("Timestamp"), ">=", xs:date($startDate)),
    cts:element-range-query(xs:QName("Timestamp"), "<=", xs:date($endDate))
   ))
)

Upvotes: 3

Related Questions