2

I can get all the URIs of the documents in a collection by using below XQuery:

for $doc in fn:collection("transform") 
return xdmp:node-uri($doc)

But, when I tried to implement this in a Javascript module in MarkLogic, it is getting only last document in the database collection.

'use strict';
declareUpdate()
var docs = fn.collection("transform");
for(var doc of docs) {
  xdmp.nodeUri(doc)
}

It is not giving all the URIs in the collection, but rather it's only returning the last URI of the document.

How can I get it to return all of the URIs?

Mads Hansen
  • 63,927
  • 12
  • 112
  • 147
Private
  • 1,661
  • 1
  • 20
  • 51

2 Answers2

1

Create an array and add each of the URIs to that array in your for loop, then either return the array:

'use strict';
declareUpdate()
var docs = fn.collection("transform");
var results = [];
for (var doc of docs) {
 results.push(xdmp.nodeUri(doc));
}
results;

or return a Sequence using Sequence.from():

'use strict';
declareUpdate()
var docs = fn.collection("transform");
var results = [];
for (var doc of docs) {
 results.push(xdmp.nodeUri(doc));
}
Sequence.from(results);

However, if you simply want to return the URIs, then it would be better/easier to use cts.uris() with a cts.collectionQuery():

'use strict';
declareUpdate();
cts.uris("", null, cts.collectionQuery("transform"));
Mads Hansen
  • 63,927
  • 12
  • 112
  • 147
  • @Seeker - please create your arrays using the array literal syntax: var results = []; Also, if you're using MarkLogic 9 I recommend that you use the let or const keywords, like so: const results = []. – Tamas Jan 18 '18 at 08:13
  • @Mads Hansen - Is there any way to read directly the uri's rather than pushing into array why because , if my collection has millions of uri's then the push uri's into array itself will take much time which impacts on perfomance . What i meant was `for $doc in fn:collection("transform") return xdmp:node-uri($doc)` where we are getting values from a single function without using array. – Private Jan 18 '18 at 17:58
  • 1
    If you just want to return the URIs of docs in a particular collection, then it would be easier to use `cts.uris()` with a `cts.collectionQuery()`. I have updated with an example. – Mads Hansen Jan 18 '18 at 21:08
1

None of the answers explain why they address the origin question, or what the core misunderstanding is. They are correct answers but its not obvious why.

There is no problem with the original code except the incorrect assumption of how JavaScript returns evaluated expressions.

The LAST evaluated expression is returned from a JavaScript 'script'.

This differs from XQuery in which the expressions accumulate into a Sequence which is returned.

Try this simple case:

'use strict;'
var i = 0
i++
i++
i++

Result:

2

NOT

[ 0 , 1 , 2 ]

That doesnt mean it didnt 'execute' "i++" 3 times, it means the resulting value is the last one.

Try your original code unchanged except in the loop 'Do Something' that has some kind of visible result -- say Console.log()

'use strict';
declareUpdate()
var docs = fn.collection("transform");
for(var doc of docs) {
  Console.log(xdmp.nodeUri(doc))
}

Then look in ErrorLog.txt (V8) of 8000_ErrorLog.txt (V9) You will see an entry for each URI.

That is WHY the suggestion to put the values into an array, since you asked "How can I get it to return all of the URIs?" - thats how you do it.

However the question "Is there any way to read directly the uri's rather than pushing into array" is entirely different. Your existing code currently does that. You just don't 'see' it because you are doing nothing with the URI but 'dropping it on the floor'

When you add the code to do whatever it is you want to do with the URI (or node), it will be executed one by one without having to load the entire sequence first.

Try it.

DALDEI
  • 3,722
  • 13
  • 9