How to count subdocuments recursively - azure-cosmosdb

I have documents in my db that look like this:
{
"id": "1"
"entityType": "node"
"childNodes": [
{
"id": "2"
"entityType": "node"
"childNodes": [
...
]
}
]
}
As a large tree structure.
I'd like to count the total number of documents and subdocuments in my collection that are of entityType = "Node".
My attempt is to get the data one level at a time manually:
SELECT VALUE COUNT(c.id) FROM c where CONTAINS(c.id, 'a|') and c.entityType = 'node'
SELECT VALUE COUNT(l.id) FROM c JOIN l in c.childNodes where CONTAINS(c.id, 'a|') and c.entityType = 'node'
SELECT VALUE COUNT(l2.id) FROM c JOIN l in c.childNodes JOIN l2 in l.childNodes where CONTAINS(c.id, 'a|') and c.entityType = 'node'

First of all, it's hard to find a smooth(direct) way to implement your needs.Surely,the manual way you mentioned in your question works.However,if you have too many layers of JSON nesting, or it's random,your way maybe inappropriate.
I would suggest you loop the result recursively to get the count of objects which contains "entityType": "node".For example, in the cosmos db stored procedure:
function sample(prefix) {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT c.childNodes FROM c where c.entityType = "node"',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) {
var response = getContext().getResponse();
response.setBody('no docs found');
}
else {
var response = getContext().getResponse();
var count = {count:1};
loopChildNodes(feed,count);
response.setBody(count);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
function loopChildNodes(array,count){
for (var i=0;i<array.length;i++){
console.log(count)
if(array[i].entityType == "node"){
count.count++;
}
if(array[i].childNodes!=null)
loopChildNodes(array[i].childNodes,count)
}
}
}
My test data:
Output:

Related

CosmosDb search datetime with millisecond precision not working when ms is .0000000Z

Have the following test data in CosmosDB.
{
"LastSuccessfulDeployment": "2022-10-08T01:30:30.0000000Z",
},
{
"LastSuccessfulDeployment": "2022-10-08T01:30:30.3816486Z",
}
Searching '2022-10-08T01:30:30.0000000Z' returns no records whereas when searching for '2022-10-08T01:30:30.3816486Z' records are being returned.
protected override IQueryable<Component> ApplyFiltersOnQueryInternal(IQueryable<Component> query, IFilter<Component> filter)
{
if (filter == null)
return query;
var componentFilter = (filter as ComponentFilter)!;
if (componentFilter.LastSuccessfulDeployment.HasValue)
query = query.Where(x => x.LastSuccessfulDeployment == componentFilter.LastSuccessfulDeployment);
return query
.Skip((componentFilter.CurrentPage - 1) * componentFilter.PageSize)
.Take(componentFilter.PageSize);
}
EntityQueryable DebugView:
-- #__componentFilter_LastSuccessfulDeployment_0='08/10/2022 01:30:30'
SELECT c
FROM root c
WHERE ((c["Discriminator"] = "Component") AND (c["LastSuccessfulDeployment"] = #__componentFilter_LastSuccessfulDeployment_0))
-- #__componentFilter_LastSuccessfulDeployment_0='12/10/2022 15:18:14'
SELECT c
FROM root c
WHERE ((c["Discriminator"] = "Component") AND (c["LastSuccessfulDeployment"] = #__componentFilter_LastSuccessfulDeployment_0))
```Code

How to return all the id's with common value for another field in cosmos sql api?

the cosmos doc is in this structure
{
orderNumber: 1,
productNumber:p1
},
{
orderNumber: 1,
productNumber:p2
},
{
orderNumber: 2,
productNumber:p3
}
how do I return the list of productsnumber within the same ordernumber.
for example, the result should be like
{
orderNumber:1,
products:{
p1,
p2
}
select c.orderNumber,count(c.orderNumber)
from c
group by c.orderNumber
I tried this query to get the count on ordernumber, which gives the product count, but how can we return the actual productNumber.
Thank you

Cosmos equivalent of map / select

clients is an array inside my doc, the following query
SELECT
f.id, f.clients
FROM f
where f.id ="35fb0733-dfa1-4932-9690-3ee5b05d89ff"
Returns
[
"id": "35fb0733-dfa1-4932-9690-3ee5b05d89ff",
{
"clients": [
{
"firstname": "Benjamin",
"surname": "Bob",
},
{
"firstname": "Rachael",
"surname": "Smith",
}
]
}
]
But I would like clients to look like :
"firstnames": [ "Benjamin", "Rachael" ]
"surnames": [ "Bob", "Smith" ]
Is this possible?
You could use the ARRAY expression w/ a subquery to achieve that.
Try this query:
SELECT
ARRAY(SELECT VALUE client.firstname FROM client IN f.clients) AS firstnames,
ARRAY(SELECT VALUE client.surname FROM client IN f.clients) AS surnames
FROM f
Just give an additional option, you could use stored procedure to get the results you want.
function sample() {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT f.id, c.firstname,c.surname FROM f join c in f.clients where f.id ="1"',
function (err, feed, options) {
if (err) throw err;
var map = {};
var firstname = [];
var surname =[];
if (!feed || !feed.length) {
var response = getContext().getResponse();
response.setBody('no docs found');
}
else {
for(var i=0;i<feed.length;i++){
map["id"] = feed[i].id;
firstname.push(feed[i].firstname);
surname.push(feed[i].surname);
}
map["firstname"] = firstname;
map["surname"] =surname;
var response = getContext().getResponse();
response.setBody(map);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Test Output:
{
"id": "1",
"firstname": [
"Benjamin",
"Rachael"
],
"surname": [
"Bob",
"Smith"
]
}

phonegap sqlite database sum query result

see the following code,
function queryData(tx) {
tx.executeSql('select sum(income) from balancesheet where id=1',
[],
rowsDataHandle,
errorCB);
}
rowsDataHandler = function(tx, results) {
var row = results.rows.item(0).income;
document.getElementById("mydata").innerHTML = 'Your Total income:\t'+ row;
};
income is an integer field.
please check the query as well. and how to get sum of all income transactions.
Try using an alias for the sum:
select sum(income) as totalincome from balancesheet where id=1
and then...
rowsDataHandler = function(tx, results) {
var row = results.rows.item(0).totalincome;
document.getElementById("mydata").innerHTML = 'Your Total income:\t'+ row;
}

how to fetch two same fields data from db [HTML5]?

this.db.transaction(function (tx)
{
tx.executeSql('SELECT tsk.*, cont.firstName, cont.lastName ,cont1.firstName, cont1.lastName, list.listId FROM tbl_tasks tsk, tbl_contacts cont,tbl_contactequests cont1, tbl_lists list WHERE (tsk.assignedId=0 or tsk.assignedId=cont.contactId or tsk.assignedId=cont1.contactRequestId) and tsk.taskCategoryType != "INBOX_NOT_ACCEPTED" and list.listId=tsk.listId and list.listId='+window.defaultlistid+' group by tsk.taskId', [], enyo.bind(this,this.queryResponse), enyo.bind(this,this.errorHandler));//call queryResponse
}.bind(this));
Now as you can see cont.firstName (Table tbl_contacts) & cont1.firstName has (Table tbl_contactequests) has same fields first name
for (var i = 0; i < len; i++)
{
list[i] = results.rows.item(i);
fname = list[i].firstName;
lname = list[i].lastName;
fullname = fname+' '+lname;
//alert(fullname);
if(list[i].assignedId==0)
{list[i].name = '';}
else
{list[i].name=fullname;}
}
with this loop i can able to featch first value of tbl_contacts field firstname.Now suppose if i can't to access tbl_contactequests table firstname.
Use AS keyword for SQL query:
'SELECT tsk.*,
cont.firstName AS cFirstName,
cont.lastName ,
cont1.firstName AS c1FirstName,
cont1.lastName, list.listId
FROM tbl_tasks tsk, tbl_contacts cont,
tbl_contactequests cont1, tbl_lists list
WHERE (tsk.assignedId=0 OR tsk.assignedId=cont.contactId OR
tsk.assignedId=cont1.contactRequestId) AND
tsk.taskCategoryType != "INBOX_NOT_ACCEPTED" AND
list.listId=tsk.listId AND list.listId='+window.defaultlistid+'
GROUP BY tsk.taskId'

Resources