how to document insert with the collections in Marklogic using XQuery - xquery

I have a requirement where in I have to insert documents with name 1 to 6 with extension .xml, set the collection as "flags" to each of the documents in one go, and insert them into a directory called America.
How can I achieve this using xdmp:document-insert?

This is a minimal example that inserts the 6 documents and sets the "flags" collection with dummy content <doc/>.
for $i in (1 to 6)
let $uri := "/America/"||$i||".xml"
return
xdmp:document-insert($uri, <doc/>,
<options xmlns="xdmp:document-insert">
<collections>
<collection>flags</collection>
</collections>
</options>)
with the URIs:
/America/1.xml
/America/2.xml
/America/3.xml
/America/4.xml
/America/5.xml
/America/6.xml

Related

How to remove collection or edge document using for loop in ArangoDB?

I'm using the latest ArangoDB 3.1 on Windows 10.
Here I want to remove the collection document and edge document using the for loop. But I'm getting an error like document not found (vName).
vName contains the many collection names. But I dunno how to use it in for loop.
This is the AQL I am using to remove the documents from the graph:
LET op = (FOR v, e IN 1..1 ANY 'User/588751454' GRAPH 'my_graph'
COLLECT vid = v._id, eid = e._id
RETURN { vid, eid }
)
FOR doc IN op
COLLECT vName = SPLIT(doc.vid,'/')[0],
vid = SPLIT(doc.vid,'/')[1],
eName = SPLIT(doc.eid,'/')[0],
eid = SPLIT(doc.eid,'/')[1]
REMOVE { _key: vid } in vName
Return output im getting from the AQL (Web UI screenshot)
vName is a variable introduced by COLLECT. It is a string with the collection name of a vertex (extracted from vid / v._id). You then try to use it in the removal operation REMOVE { ... } IN vName.
AQL does not support dynamic collection names however, collection names must be known at query compile time:
Each REMOVE operation is restricted to a single collection, and the collection name must not be dynamic.
Source: https://docs.arangodb.com/3.2/AQL/Operations/Remove.html
So, you either have to hardcode the collection into the query, e.g. REMOVE { ... } IN User, or use the special bind parameter syntax for collections, e.g. REMOVE { ... } IN ##coll and bind parameters: {"#coll": "User", ...}.
This also means that REMOVE can only delete documents in a single collection.
It's possible to workaround the limitation somewhat by using subqueries like this:
LET x1 = (FOR doc IN User REMOVE aa IN User)
LET x2 = (FOR doc IN relations REMOVE bb IN relations)
RETURN 1
The variables x1 and x2 are syntactically required and receive an empty array as subquery result. The query also requires a RETURN statement, even if we don't expect any result.
Do not attempt to remove from the same collection twice in the same query though, as it would raise a access after data-modification error.

How to retrieve a value of an attribute from the XML stored across multiple rows using Oracle-Xquery?

We are using Oracle 11g database with XMLDB installation. We are having table with XMLType columns. The structure of the XML will be same for all the rows in a table. The table will have other fiedls also.
Now I want to retrieve only the values of the particular node's attribute values from all the rows as a string with some other relational fields. The table columns retrieved can be like TemplateId, TemplateVid,TemplatepartId.
The structure of the XML can be as follows:
<Template ID=1000 VID=1>
<TemplateParts>
<Template ID="4000" VID="1"/>
<Template ID="4001" VID="1"/>
</TemplateParts>
</Template>
So the table will have data for Template with TemplateId,Vid and TemplateXML. The TemplateXML field is an XMLType field. Now I want to retrieve all the TemplateId,Vid and its refereced template partIds as an XML table. The output should be as follows:
TemplateId - TemplateVid - TemplatePartId - TemplatepartVid
1000 1 4000 1
1000 1 4001 1
So anybody comes up with a correct Xquery for the above requirement.
Your requirement is not clear but to start you off and hopefully get you some additional comment from the wider XQuery community on StackOverflow here is a quick example. Hope this helps :)
xquery version "1.0";
<html>
<head>
<title>Sample</title>
</head>
<body>
<div align="center">
<table>
<tr><th>TemplateId</th><th>TemplateVid</th><th>TemplatePartId</th><th>TemplatepartVid</th></tr>
{
let $sample as element()* := (<root><Template ID="1000" VID="1"><TemplateParts><Template ID="4000" VID="1" /><Template ID="4001" VID="1" /></TemplateParts></Template></root>)
for $e in $sample/Template
return
for $tp in $e/TemplateParts/Template
return
(<tr><td>{data($e/#ID)}</td><td>{data($e/#VID)}</td><td>{data($tp/#ID)}</td><td>{data($tp/#VID)}</td></tr>)
}
</table>
</div>
</body>
</html>
As I have mentioned in my earlier comment, I have managed to get the IDs and VIDs which is stored under the Node /Template/TemplateParts/Template from xmltype column of all the rows. The query is as follows:
select distinct x.value as TemplatePartId,Y.Value as Vid from
TempVersion t ,
xmltable('/Template/TemplateParts/Template' passing t.CONTENT columns value varchar2(10) path '#ID' ) x,
xmltable('/Template/TemplateParts/Template' passing t.CONTENT columns value varchar2(10) path '#VID' ) y
order by TemplatePartId;
If sombody know better format,please post your sample query. I need as a normal query as the above format is not supported by my ORM tool. If you look at the above query you can notice that the XMLTable expression is to be placed after the From clause. This gives trouble when I try to form this query through my LLBLGen ORM tool.

XQuery how to get whole xml document with WHERE query

I have XML db with only one collection (container) and I don't know the document names. How to get a entire XML document from db, which complies WHERE clause?
<root>
<node1>
<node2>
<node3>My Content</node2>
</node2>
</node1>
<root>
When I have queries
query 'collection("data1.dbxml")/root/node1/node2[node3 = "My Content"]/string()'
it returns a content from that node3
'My Content'
and
query 'collection("data1.dbxml")/root/ode1/node2/node3'
it returns 2 internal nodes with the content
<node2><node3>My Content</node3></node2>
But how to get whole document which complies this WHERE clause (sth like SELECT * FROM data2.dbxml WHERE node3='My Content'?
Simply use a predicate as you did in the first example:
collection("data1.dbxml")/root[node1/node2/node3 = "My Content"]
You can think of the predicate in XQuery as the WHERE in SQL and the SELECT-part is everything before.
another resolution ... after studying :)
query 'for $x in collection("data1.dbxml")
where $x/root/node1/node2/node3 = "My Content"
return $x'
or when we know the depth of node in XMLdoc and node's name
query 'for $x in collection("data1.dbxml")
where $x/*/*/*/node3 = "My Content"
return $x'
thanks W3Schools

Using ExtractValue and XMLType in MAterialized view

I'm trying to create a materialized view that will present a tabular view on XML data contained in a table. I am also hoping to use the auto refresh option to ensure the MV is always up to date.
Some background:
Oracle 10.2
table def:
CREATE TABLE AGREEMENTEXTENSIONDATA (
AGREEMENTEXTENSIONDATAID NUMBER(18) NOT NULL,
EXTENSIONDATA NCLOB,
AGREEMENTID NUMBER(18) NOT NULL)
example of extensiondata:
<Extensions>
<ExtensionData id="2" name="IncludePortfolio" type="4">true</ExtensionData>
</Extensions>
I have create a log on the table:
CREATE MATERIALIZED VIEW LOG ON AGREEMENTEXTENSIONDATA
NOCACHE
LOGGING
NOPARALLEL
WITH PRIMARY KEY
INCLUDING NEW VALUES;
I am then trying to create the following MV:
CREATE MATERIALIZED VIEW MV_ExtAgreements
REFRESH FAST ON COMMIT
ENABLE QUERY REWRITE
as
select AGREEMENTEXTENSIONDATAID,
agreementid,
extractvalue(xmltype(EXTENSIONDATA), '/Extensions/ExtensionData[#id=''1'']')
from agreementextensiondata
/
But get the following message:
ORA-30373: object data types are not supported in this context
I saw another post suggesting to use a function to extract the values from XML, but this does not work either:
create or replace function extractVARCHAR2Extension(p_xml in clob, in_number in VARCHAR2)
return varchar2 deterministic
is
begin
return xmltype(p_xml).extract('/Extensions/ExtensionData[#id=''' || in_number || ''']/text()').getstringval();
end;
/
but the following statement fails:
select extractVARCHAR2Extension(extensiondata,'2')
from agreementextensiondata
where agreementid = 136
ORA-00600: internal error code, arguments: [kghsccread1], [128], [0], [], [], [], [], []
ORA-06512: at "SYS.XMLTYPE", line 254
ORA-06512: at "ALGOV5.EXTRACTVARCHAR2EXTENSION", line 5
??
Any guidance welcome, I maybe using the wrong set of tools here.
thanks
Change p_xml in clob to p_xml in Nclob.

Auto increment with XQuery Update?

Does XQuery Update support auto increment attributes, just like auto increment fields in SQL?
I'm using BaseX as my database.
Given an answer from Christian GrĂ¼n on the BaseX mailing list, this is doable when the node one is adding is defined in the XQuery Update statement, and hence can be enhanced using an {enclosed expression} before inserting it:
You might specify the attribute counter within your XML file/database
and increment it every time when you insert an element. A simple
example:
input.xml:
<root count="0"/>
insert.xq:
let $root := doc('input.xml')/root
let $count := $root/#count
return (
insert node <node id='{ $count }'/> into $root,
replace value of node $count with $count + 1
)
I've not been able to achieve the same with an external org.w3c.dom.Document created in Java, and added to the XML database using XQJ and declare variable $doc external. Here, one might be tempted to update the "auto-increment" data after adding the document. However, the processing model defines that changes are not visible until all the commands have been queued (the Pending Update List). Hence a new document or node is, by definition, simply not visible for updates in the same FLWOR expression. So:
db:add('db1', '<counters comment-id="0"/>', 'counters')
...followed by repetitive executions of the following, will NOT work:
let $doc := document{ <note id=""><text>Hello world</text></note> }
let $count := /counters/#comment-id
return (
db:add('db1', $doc, 'dummy'),
replace value of node $count with $count + 1
for $note in /note[#id='']
return replace value of node $note/#id with $count (: WRONG! :)
)
Above, the last inserted document will always have <note id="">, and will not be updated until the next document is added. (Also, it would not work when somehow multiple documents with <note id=""> would exist.)
Though in the example above one could successfully delete the for $note in ... part and use:
let $doc := document{ <note id="{ $count }"><text>Hello world</text></note> }
...I had no luck setting <note id="{ $count }"> in the Document in the Java code, as that enclosed expression would not be replaced then.
Finally, some state for similar solutions:
[...] perform badly as it will lock out concurrent updates. You should consider using xdmp:random() to generate a 64 bit random number for your unique identifier.
In our case, the id would also be used in URLs; not too nice then.
See also XRX/Autoincrement File ID and Using XQuery to return Document IDs.
This would depend on the implementation of the underlying data-store, because the auto-increment attribute is on the column definition in relational databases.
Probably, "yes".

Resources