I have the following code that returns an array of array of results I try to use distinct-values to remove duplicates and it does nothing I have tried also removing using looping functions by comparing values with no success.

I have tried converting to "xs anyAtomicType" and using distinct values I have tried putting in json array and extracting the sub-array I have tried tokenizing, xdmp quote, string-before/after and many others

declare function local:verify-user-uri($dir as xs:string) 
{ 
   for $each in cts:uris($dir, ())
     let $uIds := (for $d in $each  
     where contains($d, "/profile.xml")
   return $d)

   return $uIds
};    

I get back duplicated result in form of:

/users/123-343-/profile.xml
/users/122-222-/profile.xml
/users/123-343-/profile.xml
/users/122-222-/profile.xml
/users/123-343-/profile.xml
/users/122-222-/profile.xml

I am expecting:

/users/123-343-/profile.xml
/users/122-222-/profile.xml

2 Answers

0
Mads Hansen On

Is it possible that you have simply invoked this function 3 times and didn't realize it?

You have declared $dir to be a single xs:string. If your $dir happened to be a sequence of strings of the same directory, or if you otherwise invoked the function 3 times with the directory variable.

It can easily happen with function mapping enabled (default behavior). https://docs.marklogic.com/guide/xquery/enhanced#id_55459

There are a couple of things that you can do as a diagnostic:

1.) Remove the explicit type on the $dir parameter in the function:

declare function local:verify-user-uri($dir) 
{ 
   for $each in cts:uris($dir, ())
   let $uIds := (for $d in $each  
     where contains($d, "/profile.xml")
     return $d)
   return $uIds
};

do you get an error executing cts:uris() that looks like this:

[1.0-ml] XDMP-ARGTYPE: )err:XPT0004) cts:uris(("/users/", "/users/", "/users/"), ()) -- arg1 is not of type xs:string?

2.) try disabling function mapping by adding the following to the prolog:

declare option xdmp:mapping "false";

and see if you then get an invalid coercion error like:

[1.0-ml] XDMP-AS (err:XPTY0004) $dir as xs:string -- Invalid coersion ("/users/", "/users/", "/users/") as xs:string

3.) You could also add something to the end of the sequence of values returned from the function to indicate how many times it has executed:

declare function local:verify-user-uri($dir as xs:string) 
{ 
   for $each in cts:uris($dir, ())
   let $uIds := (for $d in $each  
     where contains($d, "/profile.xml")
     return $d)
   return $uIds, "#"
};

And see how many times you see "#" in the result. If more than one, you are invoking the function multiple times.

0
grtjn On

Next to the good suggestions from Mads, I notice a couple of other things about your code:

  • It doesn't make sense to iterate over $each as it contains one uri only. Keep in mind that a FLWOR statement ends with a return, which tells what should be the result per item
  • Beware that the first arg to cts:uris only marks a start, not an end. If you feed in /aaa/, you also get back /bbb/ etc, though not vice versa.

To be honest, I think you are looking for cts:uri-match() instead, which would reduce your function to a one-liner:

declare function local:verify-user-uri($dir as xs:string) { 
  cts:uri-match($dir || "*/profile.xml")
};

HTH!

PS: I do recommend always disabling function mapping as Mads recommends. It can prevent a lot of confusion.