How can I change the database that a cts:search function runs against programmatically?
Right now I'm in query console.
You will probably need to use xdmp:eval, which accepts an options argument, and in there you can specify the database:
xdmp:eval("cts:search(...)", (),
<options xmlns="xdmp:eval">
<database>{xdmp:database("otherdb")}</database>
</options>)
Although on the lowest level, xdmp:eval is really what happens, the most clean option which is probably easiest to write inline is xdmp:invoke-function- and even better may be to also use an anonymous function within it. This combination allows for natural use of existing variables. If you want to go further, then also look at xdmp:apply(to add more flexability)
Furthermore, in MarkLogic 8, there is a new transaction-type called update-auto-commit which also makes it nice and clean to invoke a function inline, while waiting for the results (no spawn) and have it in its own transaction. Used properly, then the results of an update/insert are even available in the calling code.
The code sample below applies cts:search against another database and
naturally uses the variables in the main code:
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
let $query := cts:word-query("foo")
let $start := 1
let $end := 3
let $database-name := "your-other-database-name-here"
return
xdmp:invoke-function(
function() {
cts:search(doc(), $query)[$start to $end]
},
<options xmlns="xdmp:eval">
<database>{xdmp:database($database-name)}</database>
</options>)
Related
Running the following xquery directly in eXide (Eval) it works fine, adding the XML files in MyFSdirectory into the MyCollectionPath:
xquery version "3.1";
let $selected_directory:= 'MyFSdirectory'
let $source-directory := $selected_directory
let $target-collection := 'MyCollectionPath'
return
xmldb:store-files-from-pattern($target-collection, $source-directory, '*.xml')
But when I add it to a function and call it from my app, the store-files-from-pattern is not doing the job (no errors are shown but files are not uploaded), the check point is printed in my screen, so the function is being called correctly. Any hints?
declare function app:upload_file($node as node(), $model as map(*)) {
let $selected_directory:= "MyFSdirectory"
let $source-directory := $selected_directory
let $target-collection := "MyCollectionPath"
return
<p>check point</p> |
xmldb:store-files-from-pattern($target-collection, $source-directory, '*.xml')
};
This sounds like a permissions issue. In other words, when you run the script in eXide, you're likely running as a user (e.g., "admin") with write permissions on the target collection, but in your application the script is likely running as a guest user without the required permission to write to the target collection.
To troubleshoot, add an expression calling xmldb:login() to your app:upload_file() function, supplying the credentials for the user you use in eXide.
If elevating privileges this way works, then the next step would be to consider setting appropriate permissions on the target collection or setting applying setuid or setgid on the module that writes to the database.
I'm setting up a database with roxy, which is different from the "documents" database. I want to insert a config file into that database.
I have this function in xquery ml-1.0
xquery version "1.0-ml";
declare namespace appsetup = "http://kittens.com.au/appsetup";
declare function appsetup:setup-day0($root,$content-db){
(: some values :)
let $m := map:new ()
let $_ := map:put ($m, "Kittens-Forever",xdmp:parse-dateTime("[Y0001]-[M01]-[D01]", "2999-12-31"))
let $_ := map:put ($m, "Kittens-Never", xdmp:parse-dateTime("[Y0001]-[M01]-[D01]", "1899-12-31"))
let $_ := map:put ($m, "Kittens-Load-Root", $root)
return xdmp:document-insert ("/ksys/smap", <s:map>{$m}</s:map>,
(xdmp:permission ("Kittens-role", "read"),
xdmp:permission ("Kittens-role", "update")) )
};
The xdmp:document-insert inserts the document in to the default "documents" database. I had a look around, and i couldn't find a way to say load this document into this database. I only found a way to insert the document into a particular forest with xdmp:document-load (https://docs.marklogic.com/xdmp:document-load).
Is there a way for me to say load this thing into this database, preferably just as a xquery parameter?
xdmp:document-insert does not insert into the Documents database by default. It inserts into the database defined in the application server configuration. The idea is that you have an application server that you use to interface with the database.
Some notes:
Use an app server configured for your database.
Or use the REST API that has a parameter for this
Or use HTTP rewrite rules to dynamically change the database based on a user, URI or query parameter
Or use xdmp:eval or its derivatives (spawn, invoke, invoke-function) which all have an option to define which database to use.
For your particular sample, I would suggest that you use xdmp:invoke-function.
I have this xquery as follows:
declare variable $i := doc()/some-element/modifier[empty(modifier-value)];
$i[1]/../..;
I need to run this query on Marklogic's Qconsole where we have 721170811 records. Since that is huge number of record, I am getting timeout error. Is there any way I can optimize this query to get the result?
P.S. I cannot request amdin to increase the timeout time.
Try creating an element range index (or a path range index if the target element is not unique) and using a cts:values() lexicon lookup.
That way, the request can read the values from the range index instead of having to read each document.
See:
http://docs.marklogic.com/guide/search-dev/lexicon
You could use xdmp:spawn, create a library when you will make the query, get the documents, iterate the result collecting 1000 documents per iteration and call another xdmp:spawn to process the information from that dataset, I would suggest summarize the result to return only the information you will need to don't crash the browser, at the end should look something like this:
xdmp:spawn("process.xqy")
into the library process.xqy
function local:start-process(){
let $docs := (....)
let $temp := for $x in $docs[$start to $end]
return local:process-dataset($temp) (: Could use spawn here too if you want :)
return xdmp:spawn("collect.xqy",$temp)
}
local:start-process()
compact-data function should create a file or a set of files with your data, this way the server will run all the process and in some minutes you will be available to see your data without problems.
You don't want to run something like doc() or xdmp:directory - just returns a result set that will kill you every time. You need to lower your result set by a lot.
A few thoughts:
You want to have as much done in MarkLogic's d-node, and the least work done in the e-node as possible. This is a way over-generalization, but for the most part I look at it like d-node stuff is data, indexes, lexicon work, etc. e-node stuff handles xQuery and such. So, in your example, you're definitely working out the e-node more than you need to.
You're going to want to use cts:search, as it uses indexes, not xPath to resolve your query. So, something like this:
declare variable $i := cts:search(fn:collection(),
cts:element-query(xs:QName("some-element"),
cts:element-value-query(xs:QName("modifier"), "", "exact")
)
)[1];
This will return document-node's, which it looks like what you were wanting with the $i[1]/../... This searches the xPath some-element for a modifier that is empty.
Please create element range index and attribute range index and use cts:search if you are familiar with marklogic it will be easy for you to write the query.
I tried to update embedded triples in marklogic using xquery but it seems to be not working for embedded triples however the same query is working for other triples
can you tell me if there is some other option which needs to specified while performing an update on embedded triples.
The code i used is
xquery version "1.0-ml";
import module namespace sem = "http://marklogic.com/semantics"
at "/Marklogic/semantics.xqy";
let $triples := cts:triples(sem:iri("http://smartlogic.com/document#2012-10-26_DNB.OL_(Citi)_DNB_ASA_(DNB.OL)__Model_Update.61259187.xml"),()())
for $triple in $triples
let $node := sem:database-nodes($triple)
let $replace :=
<sem:triple>
<sem:subject>http://www.example.com/products/1001_Test
</sem:subject>
{$node/sem:predicate, $node/sem:object}
</sem:triple>
return $node ! xdmp:node-replace(., $replace)
My document contains the following triple
<sem:triples xmlns:sem="http://marklogic.com/semantics">
<sem:triple>
<sem:subject>http://smartlogic.com/document#2012-10-26_DNB.OL_(Citi)_DNB_ASA_(DNB.OL)__Model_Update.61259187.xml</sem:subject>
<sem:predicate>http://www.smartlogic.com/schemas/docinfo.rdf#cik</sem:predicate>
<sem:object>datatype="http://www.w3.org/2001/XMLSchema#string</sem:object>
</sem:triple>
</sem:triples>
and i want this particular subject to change into something like this
<sem:subject>http://www.example.com/products/1001_Test</sem:subject>
But when i use the xquery to update it , it does not alter anything, the embedded triple in the documents remains the same.
Because when i tried to see if any of the results have changed to the subject i specified it returned me no results.
I used the following query to test.
SELECT *
WHERE {
<http://www.example.com/products/1001_Test> ?predicate ?object
}
You need to add the option 'all' when you ask for the database nodes backing the triple: sem:database-nodes($triple, 'all').
To be perfectly honest, I am not 100% sure why, but I think this is because your sem:triples element is not the root element of the document it appears on.
I have simple task to do but unable to find the exact solutions for this.I have saved a file as abc.xml in MarkLogic.How can i rename the file as some example.xml using XQuery?
Code which I tried:
xquery version "1.0-ml";
xdmp:document-rename ("/aaa.xml","/final.xml");
This is showing an error.
There is no way, that I know of, to change the document URI of an existing document. The only way I can think of is to create a new document with the same content and the new URI, and delete the existing one, in the same transaction.
Where it gets tricky is to make sure to preserve the ownership, the permissions, all the properties, the property document, make sure that the old URI is not used anywhere to link to the existing document, etc.
But usually, the document URI is never really used. You should first considering whether you really need to rename the document, and why.
(Note that saying "this is showing an error" is rarely useful on SO or on mailing lists, if you do not show what the error is.)
Florent is correct, a true 'rename' is not possible, or perhaps not even meaningful. ( analogy - rename a file from one disk to another )
"Move" however is meaningful (copy then delete in a transaction).
Defining "Move" is use case dependent - i.e. what metatdata also needs to 'move' ? permissions? collections ? document properties ? inherited permissions ?
xmlsh (http://www.xmlsh.org) implements a 'rename' (http://www.xmlsh.org/MarkLogicRename) command for the marklogic extension which is really a 'move', with the implemenation borrowed from postings on markmail (http://markmail.org/)
The implementation is the following XQuery - it doesnt do everything you might want and it might do more then you want. YMMV
https://github.com/DALDEI/xmlsh/blob/master/extensions/marklogic/src/org/xmlsh/marklogic/resources/rename.xquery
( it was also written long ago - it is likely to benefit from improvement )
I have working example this works for me.
xquery version "1.0-ml";
declare function local:document-rename(
$old-uri as xs:string, $new-uri as xs:string)
as empty-sequence()
{
xdmp:document-delete($old-uri),
let $permissions := xdmp:document-get-permissions($old-uri)
let $collections := xdmp:document-get-collections($old-uri)
return xdmp:document-insert(
$new-uri, doc($old-uri),
if ($permissions) then $permissions
else xdmp:default-permissions(),
if ($collections) then $collections
else xdmp:default-collections(),
xdmp:document-get-quality($old-uri)
)
,
let $prop-ns := namespace-uri(<prop:properties/>)
let $properties :=
xdmp:document-properties($old-uri)/node()
[ namespace-uri(.) ne $prop-ns ]
return xdmp:document-set-properties($new-uri, $properties)
};
(: function call :)
local:document-rename ("/opt/backup/x.xml","y.xml");
MarkLogic has a tutorial up addressing file renaming (moving):
https://developer.marklogic.com/recipe/move-a-document/
Importantly, it uses the function xdmp:lock-for-update() to prevent modifications to the source file while it is being copied to the target location.
Also, if you are doing a batch renaming you'll want to make sure that each file URI you rename corresponds to a document in the database or you'll get runtime errors.