limit the result using cts:collection-match in marklogic - xquery

I have 2 collections in collections.
/test/1
This has 10 documents with id
test1_1
test1_2
.....
test1_10
/test/2
This has 20 documents with id as follows
test2_1
test2_2
.....
test2_20
Query:
let $result := cts:collection-match("/test/*")
let $id :=(
fn:distinct-values(
for $doc in fn:collection(result)
order by $doc//timestamp descending
return $doc//timestamp/text()
)[1 to 5]
)
return $id
I want to return the top 5 documents from each collection descending order of timestamp but it returns only 5 documents not 10 i.e. top 5 from each collection

When $result is a sequence of greater than one item, writing for $doc in fn:collection($result) aggregates all of the documents from multiple collections into a single sequence. You need to iterate over collections first, then iterate over the values in each collection, ordered and limited.
let $collections := cts:collection-match("/test/*")
let $id :=
for $collection in $collections
return
fn:distinct-values(
for $doc in fn:collection($collection)
order by $doc//timestamp descending
return $doc//timestamp/string()
)[1 to 5]
return $id

Related

XQuery get data based on distinct values

My xml is like this:
full xml at inputxml
<course>
<reg_num>10616</reg_num>
<subj>BIOL</subj>
<crse>361</crse>
<sect>F</sect>
<title>Genetics and MolecularBiology</title>
<units>1.0</units>
<instructor>Russell</instructor>
<days>M-W-F</days>
<time>
<start_time>11:00AM</start_time>
<end_time>11:50</end_time>
</time>
<place>
<building>PSYCH</building>
<room>105</room>
</place>
</course>
I need to take distinct values for courses and return instructors that teach those courses.
This is my current code:
let $x := doc("reed.xml")/root/course
for $y in distinct-values($x/title)
let $z := $y/instructor
return ( {data($y)} ,{data($z)})
What am i doing wrong
In the code that you posted, the for loop is iterating over the sequence of distinct title string values.
You can't XPath into those strings.
Rather, you want to XPath into the $x courses and use the $y in each iteration to select those course elements that have the title equal to $y, then select it's instructor.
let $x := doc("reed.xml")/root/course
for $y in distinct-values($x/title)
let $z := $x[title = $y]/instructor
return ( {data($y)} ,{data($z)})
In XQuery 3.1 you can do this with group by.
for $course := doc("reed.xml")/root/course
group by $title := $course/title
return ( <title>{$title}</title> ,
<instructors>{$course/instructor}</instructors> )

How to add a count number to an array of data : Doctrine

In fact, after returning a result of data from the database using Doctrine,
I'm trying to add the row count number, without calling another query request.
This is my function:
public function search(QueryBuilder $qb, string $search)
{
$qb = $qb->addSelect('COUNT(n) as count');
$search = $this->escape($search);
$qb->andWhere(
$qb->expr()->like('n.title', $qb->expr()->literal('%'.$search.'%'))
);
$qb->setMaxResults(2);
}
This is my DQL:
SELECT n, COUNT(n) as count FROM CoreBundle\Entity\News n LEFT JOIN n.category c WHERE n.title LIKE '%re%'
And I need to return as a result a all my data with a count key that refer to the number of rows.
The problem that I'm getting only the first row with id = 1, and it seems that the count number is correct.
So the result should by something like that:
['count' => 2 , [Newsn1,Newsn2]
Don't tell me to use array_count because I need to get the count of rows in the database, and I have a setMaxResults function, so I will not get a real number of rows.
I don't know the configuration of your table, I just can imagine. So, here's my try:
For getting counts for all titles in your table:
# SQL
SELECT COUNT(id) AS count, GROUP_CONCAT(title SEPARATOR ', ') AS titles FROM newses GROUP BY title
# DQL. assuming you are using a Repository method:
$qb = $this->createQueryBuilder('n');
$qb
->select("COUNT(n.id) AS count, GROUP_CONCAT(n.title SEPARATOR ', ') AS titles")
->leftJoin('n.category', 'c')
->groupBy('n.title')
;
return $qb->getQuery()->getArrayResult();
For getting counts for a particular title:
# SQL
SELECT COUNT(id) AS count, GROUP_CONCAT(title SEPARATOR ', ') AS titles FROM newses WHERE n.title LIKE '%news%' GROUP BY title
# NewsRepository.php
public function getTitlesCount($title)
{
$qb = $this->createQueryBuilder('n');
$qb
->select("COUNT(n.id) AS count, GROUP_CONCAT(n.title SEPARATOR ', ') AS titles")
->leftJoin('n.category', 'c')
->where('n.title LIKE :title')
->setParameter('title', "%{$title}%")
->groupBy('n.title')
;
return $qb->getQuery()->getArrayResult();
}

How to get the difference URI between 2 collection in marklogic

I have two collections .
I need to get difference uri between the two collections based on the file name.
Example Scenario :
Collection 1:
/data/1.xml
/data/2.xml
/data/3.xml
collection 2:
/test/1.xml
/test/2.xml
/test/3.xml
/test/4.xml
/test/5.xml
output:
/data/1.xml
/data/2.xml
/data/3.xml
/test/4.xml
/test/5.xml
Using set delta as David suggests is correct, but you will need to first generate filename keys for the URIs. Maps are very helpful for this, which make it easy to keep a filename key associated with its original URI.
First generate two maps with filename keys and URI values. Then, using set delta on the map keys, generate a sequence of diff filenames. Then get the URIs for those filenames from its source map:
let $x := (
"/data/1.xml",
"/data/2.xml",
"/data/3.xml")
let $y := (
"/test/1.xml",
"/test/2.xml",
"/test/3.xml",
"/test/4.xml",
"/test/5.xml")
let $map-x := map:new($x ! map:entry(tokenize(., '/')[last()], .))
let $map-y := map:new($y ! map:entry(tokenize(., '/')[last()], .))
let $keys-diff-y := map:keys($map-y)[not(. = map:keys($map-x))]
let $diff-y := map:get($map-y, $keys-diff-y)
return ($x, $diff-y)
Two alternative solutions:
First approach, put each of the items in the map, using a consistent key(substring after the last slash), and then select the first item in the map for each key:
let $x := (
"/data/1.xml",
"/data/2.xml",
"/data/3.xml")
let $y := (
"/test/1.xml",
"/test/2.xml",
"/test/3.xml",
"/test/4.xml",
"/test/5.xml")
let $intersection := map:map()
let $_ := ($x, $y) ! (
let $key := tokenize(., "/")[last()]
return
map:put($intersection, $key, (map:get($intersection, $key), .))
)
return
for $key in map:keys($intersection)
for $uri in map:get($intersection, $key)[1]
order by number(replace($uri, ".*/(\d+).xml", '$1'))
return $uri
Second approach, ensure that only the first item is set for a given key:
let $x := (
"/data/1.xml",
"/data/2.xml",
"/data/3.xml")
let $y := (
"/test/1.xml",
"/test/2.xml",
"/test/3.xml",
"/test/4.xml",
"/test/5.xml")
let $intersection := map:map()
let $_ := ($x, $y) ! (
let $key := tokenize(., "/")[last()]
return
if (fn:exists(map:get($intersection, $key))) then ()
else map:put($intersection, $key, .)
)
return
for $uri in map:get($intersection, map:keys($intersection))
order by number(replace($uri, ".*/(\d+).xml", '$1'))
return $uri
The order by is optional, but with maps you may not have consistent ordering of the keys. Customize for what you need (i.e. /data/ uris first, and then /test/ uris, etc), or remove if you don't care about the order of the URIs.
Set notation:
Delta: (Yields 'a')
let $c1 := ('a', 'b', 'c')
let $c2 := ('b', 'c', 'd')
return $c1[fn:not(.= $c2)]
Intersection: (Yields b,c)
let $c1 := ('a', 'b', 'c')
let $c2 := ('b', 'c', 'd')
return $c1[.= $c2]
Reverse c1 and c2 for the other two permutations.
For a good read, check out this post from Dave Cassel

How to count number of elements with AQL?

I need to count elements that was in result of SQL query:
db._query('FOR v in visitors FILTER v.ip == "127.0.0.1" return COUNT(v.guid) ')
This request is return my a length of every GUID, but I need to get total number of GUIDs for example: 2.
You need to use the result of the query as input for the COUNT function, and then RETURN this result.
You can replace the RETURN value of the actual query by 1 for performance reasons:
RETURN COUNT(FOR v IN visitors FILTER v.ip == "127.0.0.1" RETURN 1)
Version from 2022!
FOR m IN messages
FILTER DATE_HOUR(m.date) == 3
COLLECT WITH COUNT INTO length
RETURN length

count total rows returned by query in doctrine 2 zf2

$countQuery = $qb->select('q.id,d.name,d.numbers')
->from('Application\Entity\quests', 'q');
->leftJoin('q.dots', 'd');
$query1 = $countQuery->getQuery()->getResult();
now how would i get the total number of results returned
**i don't want to write 2 queries** bcz it will increase the execution time than
i have tried
$countQuery = $qb->select('count(q.id) as total_results,d.name,d.numbers')
->from('Application\Entity\quests', 'q');
->leftJoin('q.dots', 'd');
$query1 = $countQuery->getQuery()->getResult();
but its not working
The getResult() method returns an array of results. To count total results returned by getResult() method simply count it with PHP function count.
$countQuery = $qb
->select('q.id,d.name,d.numbers)
->from('Application\Entity\quests', 'q')
->leftJoin('q.dots', 'd');
$query1 = $countQuery->getQuery()->getResult();
$totalResults = count($query1);
If you want to paginate your query then in case of counting total rows you need to execute two queries. One for paginated results and other to count all rows in the database.

Resources