Marklogic -How to add the collection name in cts:uris - xpath

Query:
let $collection := "sampledata"
for $uri1 in cts:uris((),(),(
cts:element-query(xs:QName("root"),
cts:and-query((
cts:element-attribute-value-query(xs:QName("root"),xs:QName($value1),$value2),
cts:element-attribute-value-query(xs:QName("root"),xs:QName($value3),$value4),
cts:element-value-query(xs:QName("year"),$value5),
cts:element-value-query(xs:QName("month"),$value6),
cts:element-attribute-value-query(xs:QName("num"),xs:QName("value"),$value7)
)))) )
return $uri1
How to add the collection name in above mentioned xquery.

You can use cts:collection-query(), as in:
cts:and-query((
cts:collection-query("sampledata"),
cts:element-query(...)
))
See:
http://docs.marklogic.com/cts:collection-query
By the way, when just returning the uri, there's no need the for/return iteration. The result is the same as just returning cts:uris().
Hoping that helps,

Related

Xpath search string to cts:search

I'm trying to use the Xpath string user input in cts:search query to get the matching nodes from the database.
Sample query used :
let $query := "/book/chapter/chapter-meta/meta/meta-value[.='book-title']"
let $results := cts:search($query, cts:and-query(()), (), 0.0)
return $results
The above one is throwing error as XDMP-UNSEARCHABLE, so I tried
let $query := "/book/chapter/chapter-meta/meta/meta-value[.='book-title']"
let $results := cts:search(xdmp:value($query), cts:and-query(()), (), 0.0)
return $results
and this also resulted in the same error.
But when the Xpath is passed directly to cts:search like below ,it is giving results
cts:search(/book/chapter/chapter-meta/meta/meta-value[.='book-title'], cts:and-query(()), (), 0.0)
Could you please suggest how to convert the Xpath string to a proper value for the cts:search to get results like the last query?
Thanks in advance!

How to avoid duplicated rows from my result array when using where clause

I need the names of the users that applied both the time I sent from my controller and time = double, so I need to display the results from this function but it duplicates the results, is there a way to resolve this?
The names of the users that picked time=double at a specific day, displays on everyday.
public function get_Shifts($day,$time){
$this->db->select('user.fullname');
$this->db->from('shifts');
$this->db->join('user', 'shifts.user_id = user.id', 'left');
$this->db->where('day=', $day);
$this->db->where('time=',$time);
$this->db->or_where('time=', $double);
$query = $this->db->get();
return $query->result_array();
}
I tried adding this line and it didn't help: $this->db->distinct();
Since Codeigniter 3 you can use it's Query Grouping functions:
Query grouping allows you to create groups of WHERE clauses by
enclosing them in parentheses. This will allow you to create queries
with complex WHERE clauses
In your case, you can use:
$this->db->group_start()
$this->db->where('day', $day);
$this->db->where('time', $time);
$this->db->group_end()
$this->db->or_where('time', $double);
this will generate something like:
WHERE ( (`day` = '2020-04-23' AND `time` = '16:00' ) OR `time` = true )
edit to respond to comment: to create an output like: WHERE ( (day = '2020-04-23' AND (time = '16:00' OR time = true ) )
you use this approach:
$this->db->where('day', $day);
$this->db->group_start()
$this->db->where('time', $time);
$this->db->or_where('time', $double);
$this->db->group_end()
note: the correct way to use CI where() function is:
$this->db->where('day', $day); and not $this->db->where('day=', $day);
There should be an error while using
$this->db->where('day=', $day);
$this->db->where('time=',$time);
$this->db->or_where('time=', $double);
The right way to use where clause
$this->db->where('day', $day);
$this->db->where('time',$time);
$this->db->or_where('time', $double);
And if you are getting duplicate data for the above query, pass column name to the distinct like :-
$this->db->distinct('user.fullname');

eXist-db collection sort

Following on from this question about navigating collections using pos:
In eXist 4.7 I have a collection in myapp/data/ which contains thousands of TEI XML documents. I use the following solution from Martin Honnen to get the document before and after a certain document
let $data := myapp/data
let $examples := $data/tei:TEI[#type="example"]
for $example at $pos in $examples
where $example/#xml:id = 'TC0005'
return (
$examples[$pos - 1],
$example
$examples[$pos + 1]
)
With this I would have expected $examples[$pos - 1] to produce document 'TC0004' and $examples[$pos + 1] to produce 'TC0006' (based on the sort order seen in eXide collection navigation view for example). They do not, producing the inverse instead.
Honnen and Michael Kay responded that
ordering of documents within a collection is very much processor-dependent
Applying an order by $example/#xml:id ascending clause did not change the result for the better.
So, the question is how can I impose an alpha-numeric order on $data?
Many thanks.
It seems at the XQuery level you can change let $examples := $data/tei:TEI[#type="example"] to
let $examples := sort($data/tei:TEI[#type="example"], (), function($e) { $e/#xml:id })
(assuming the XQuery/XPath 3.1 higher-order sort function is available) or to
let $examples := for $e in $data/tei:TEI[#type="example"] order by $e/#xml:id return $e
using the order by clause.
I don't know whether exist-db has some way to impose an order during the creation or during the selection of a collection.
Based on experience with older versions of eXist, the $pos value while going through a loop is not the sorted position order. It is the position while going through.
What you first want to do is create an ordered list, then get the three items from the list you're looking for.
let $data := myapp/data[tei:TEI/#type eq 'example']
let $examples := for $e in $data order by $e/#xml:id ascending return $e
let $pos := index-of($examples/#xml:id, 'TC0005')
return if (count($pos) eq 1) then (
if ($pos gt 1) then $examples[$pos - 1] else (),
$examples[$pos]
$examples[$pos + 1]
) else ()
A potential problem with this approach is that you'll have to sort all items every time. Creating a sorted cached list may alleviate this problem and would also allow for a much more efficient query, where you can use preceding-sibling and following-sibling from the query result.
Another potential solution, if the naming convention for the IDs is consistent, would be to query the before and after IDs.
The check to see if there is one item in $pos is to prevent cases where #xml:id is not unique (yes, that would be against the spec, but it happens in real world data) or no item exists. Keep in mind that index-of returns an array of indexes - 0 or more.

Marklogic how to construct a cts query

I have a Oracle query and would like to transform into Marklogic cts query. It looks like Marklogic CTS doesn't allow to have "and-query" inside of "and-query". I am not sure how Marklogic works. Thanks in advance.
Where clause query:
where (collection = "TRBA" AND fulltext = 1
AND (dnta = "Briefing" OR dnta = "Conference" OR snta = "Workshop"
OR snta = "Published in" AND (snta = "this article" OR dnta = "Journal")
)
AND (cand IN ("Research","Development Center") OR scn IN("424778","98814","393825"))
Translate into Marklogic:
let $uris:= cts:uris(
(),
(),
cts:and-query((
cts:collection-query("/dbs/"TRBA"),
cts:element-value-query(xs:QName("meta:FullTextExists"),"1"),
cts:field-word-query("dnta",("briefing","conference")),
cts:or-query((
cts:element-word-query(xs:QName("meta:snta"),("this article")),
cts:field-word-query("dnta",("Journal")),
cts:and-query((
cts:or-query((
cts:field-word-query("cand", ("Research","Development Center"))
cts:field-word-query("scn",("424778","98814","393825"))
))
))(:inside and-query:)
))(:or-query:)
))(:outside and-query:)
return fn:doc($uris)
There are basic syntax errors in your code above: missing parens, extra double quotes
I don't think you want word query as the translation for "="; word query just says that word appears somewhere in the field in question; I would think that would be a value query instead.
You might want to take a look at cts:parse which takes a string with ANDs and ORs etc. plus bindings for fields and parses a query string into a cts:query
That said, if you assume the AND mixed in with the ORs binds to the closest clause, i.e. as parenthesized so:
(collection = "TRBA" AND
fulltext = 1 AND
(dnta = "Briefing" OR
dnta = "Conference" OR
snta = "Workshop" OR
(snta = "Published in" AND (snta = "this article" OR dnta = "Journal"))
) AND
(cand IN ("Research","Development Center") OR
scn IN ("424778","98814","393825"))
then I would translate this something like this:
cts:and-query((
cts:collection-query("/dbs/TRBA"),
cts:element-value-query(xs:QName("meta:FullTextExists"),"1"),
cts:or-query((
cts:field-value-query("dnta",("Briefing","Conference")),
cts:field-value-query("snta","Workshop"),
cts:and-query((
cts:field-value-query("snta","Published in"),
cts:or-query((
cts:field-value-query("snta","this article"),
cts:field-value-query("dnta","Journal")
))
))
)),
cts:or-query((
cts:field-value-query("cand",("Research","Development Center")),
cts:field-value-query("scn",("424778","98814","392825"))
))
))
It is a pretty direct mapping.
You simply have several typos in your code. There's an extra double quote in the collection-query and you're missing a comma between items in the last or-query.
Once fixing those the code will run. But a pro tip: don't ever fetch URIs only to fetch documents. You're wasting effort. Just fetch the documents directly with a search passing the query.
let $q := cts:and-query((...))
return cts:search(doc(), $q)[1 to 10]
You probably want to add a limit like [1 to 10] as well unless you really intend to return the full result set.

result_array() data in where clause in OR condition : Active records Codeigniter

result_array() for a query gives the following :
Array ( [0] => Array ( [id] => 1 ) [1] => Array ( [id] => 4 ) )
I want to use id=1 and id=4 in the where clause in the OR condition like the following :
$this->db->where_in('id',$query->result_array());
But the above causes error. Is there any direct way of doing the same?
You can simply use array_column
array_column($query->result_array(), 'id')
here is reference to it.
$result = $roleIdQuery->result_array();
$column = array_map(function($sub)
{
return $sub['id'];
}, $result);
I used this. Sadly.
because it has arrays within that array.
$ids=array();
$resultArray=$query->result_array();
foreach($resultArray as $result){
$ids[]=$result['id'];
}
$ids // this is what you need to pass now..
If you change your original query to use GROUP_CONCAT. Not an option in Active Record so would need to write your own SQL. something like
$query= $this->db->query('SELECT GROUP_CONCACT(id) AS ids FROM table WHERE condition=true');
Then you should be able to do
$this->db->where_in('id',$query->result_array()[0]['ids']);
Just noticed your on 5.3 so unfortunately that means this won't work you will have to do.
$result = $query->result_array();
Then pass in $result[0]['ids']

Resources