Azure Cosmos DB SQL API - #Query - azure

I have a Azure Cosmos DB Container 'RouteZipcodes' container. It will have json documents with each route and zipcodes that each route is serving. Below is the sample data stored in cosmos DB
{
"id": "2347z3e8-850d-364a-92d2-4fcae2fa5642",
"routeName": "THORN1",
"zips": [
{ "zipCode": "80373" },
{ "zipCode": "80371" },
{ "zipCode": "80020" },
{ "zipCode": "80370" },
{ "zipCode": "80021" },
{ "zipCode": "80040" },
{ "zipCode": "80602" },
{ "zipCode": "80372" }
],
"status": "A"
}
When I execute below query from portal:
SELECT r.routeName as routeName
FROM routeZipcodes r
JOIN rz in r.zips
where rz.zipCode = "80602"
Below is result:
[ { "routeName": "THORN1" } ]
When I am trying to run same query from Spring boot app, and am not getting any result. Below is my respository
#Repository
public interface RouteZipcodesRepository extends CosmosRepository<RouteZipcodes, String> {
Optional<RouteZipcodes> findById(String id);
Optional<List<RouteZipcodes>> findByHubName(String hubName);
Optional<RouteZipcodes> findByRouteName(String routeName);
// #Query("SELECT r.routeName FROM routeZipcodes r JOIN rz in r.zips where rz.zipCode = \"#zipcode\"")
// String findByZipCode (#Param("zipcode") String zipcode);
#Query("SELECT r.routeName as routeName FROM routeZipcodes r JOIN rz in r.zips where rz.zipCode = \"#zipcode\"")
List<IRouteNameByZipcode> findByZipCode (#Param("zipcode") String zipcode);
}
other methods are working as expected. Only query written with #query is not giving results when the same was working in portal.

Related

Order result resolved via resolver in graphql + apollo server + nodejs

I am trying to order an array returned by resolver in GraphQL.
I can only think of way of ordering data using DB Query, but how can we order data that GraphQL resolves using its resolver functions?
Below is my Query resolver:
getAllNotifications: (
_parent,
_args: { authorId: string },
context: Context
) => {
return context.prisma.blog.findMany({
where: {
authorId: _args.authorId,
},
orderBy: {
created_at: "desc",
},
});
},
And my query:
query Query($authorId: String) {
getAllNotifications(authorId: $authorId) {
title
comment {
id
created_at
}
}
}
And result:
{
"data": {
"getAllNotifications": [
{
"title": "First Ride! ",
"comment": [ <--- I am trying to order this comment array using created_at date
{
"id": "cl8afqaqx001209jtxx7mt5h6",
"created_at": "2022-09-20T16:53:07.689Z"
},
{
"id": "cl8agiq71001509l27or7oxyd",
"created_at": "2022-09-20T17:15:14.077Z"
},
{
"id": "cl8ahmvrm003109l8dp684bn6",
"created_at": "2022-09-20T17:46:27.538Z"
},
{
"id": "cl99kj24p002609iajdbpycg0",
"created_at": "2022-10-15T06:59:24.169Z"
}
]
}
]
}
}
I didn't found anything in Graphql docs regarding ordering data returned by resolver
GraphQL doesn't have functions for selection and ordering, those are jobs that resolvers must do.
Add a resolver for comment that sorts the comment array. Your existing sort just sorts based on the created_at date of the post.

Conditionally adding term and multi_match filters to elasticsearch with nodejs client

I am using ElasticSearch 7.9 with a nodejs client. I have the following query :
{
"query": {
"bool": {
"must":[
{ "terms" : { "id" : ["5f0d06fb5112231eb89eb819", "5f0d06fb5112231eb89eb817"] } },
{"query_string": {
"query": "(News) OR (Entertainent)",
"fields": [ "topics", "subTopics", "categories"]
}
},
{
"multi_match": {
"query": "publisher",
"fields": ["text", "name", "title", "subtitle", "description"]
}
}
]
}
}
}
I want to be able to conditionally add the terms filter for id if list of ids coming in to the nodejs/js function is not empty. Similarly for the multi_match query text as well. Add the multi_filter only if the incoming text is not empty
Should all queries be pre-constructed or is it possible to have conditional blocks and add only if the empty text or array of Ids are not empty.
My current method expects both ids and text input to the method to have valid values but these could be empty. Do I separate methods to handle the empty conditions
export const searchResults = async (text, ids) => {
const response = await client.search({
index: "new_index", //customer.id
type: "_doc",
body: {
query: {
bool: {
must: [
{terms: {"id": ids}},
{query_string: {
query: "(News) OR (Entertainent)",
fields: [ "topics", "subTopics", "categories"]
}
},
{
multi_match: {
query: text,
fields: ["text", "name", "title", "subtitle", "description"],
}
}
],
}
}
},
});
return response?.hits?.hits.map(({_source}) => _source) || [];
};
any help is really appreciated.
In a production environment and managing client based applications you should use search-templates, where you can use conditional blocks of queries. Besides, if you would want to change your query you would not neet to redeploy your app, just change it on ES.

LEFT JOIN in Azure CosmosDB SQL API

I have used JOIN in Azure Cosmos DB collection using SQL API to query documents.
I have two contact documents, one is with property Address and another one is without address.
I need to get the address list of all the persons(including the persons who is not having any address). I have used the below query to do this.
But it gives the person list who is having address.
Is there any way to do LEFT JOIN?
Query:
SELECT base.FirstName, base.LastName, Address.City FROM ContactPerson
base JOIN Address IN base.Address
Sample Document:
[
{
"FirstName": "Saravana",
"LastName": "Kumar",
"Address": [
{
"City": "aaaa"
},
{
"City": "bbbb"
}
]
},
{
"FirstName": "Jayanth",
"LastName": "T"
}
]
Expected output:
[
{
"FirstName": "Saravana",
"LastName": "Kumar",
"City": "aaa"
},
{
"FirstName": "Saravana",
"LastName": "Kumar",
"City": "bbbb"
},
{
"FirstName": "Jayanth",
"LastName": "T"
}
]
Actual Output:
[
{
"FirstName": "Saravana",
"LastName": "Kumar",
"City": "bbbb"
},
{
"FirstName": "Saravana",
"LastName": "Kumar",
"City": "bbbb"
}
]
As i know, left join is not supported by cosmos db so far,you could vote up this thread.
As workaround,i suggest you using 2 different sql in stored procedure, then merge the results in it.
1.SELECT base.FirstName, base.LastName FROM ContactPerson base where NOT IS_DEFINED(base.Address)
2.SELECT base.FirstName, base.LastName, Address.City FROM ContactPerson base JOIN Address IN base.Address
SP:
function sample() {
var collection = getContext().getCollection();
var array = [];
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT base.FirstName, base.LastName, Address.City FROM ContactPerson base JOIN Address IN base.Address',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) {
var response = getContext().getResponse();
response.setBody('no docs found');
}
else {
array.push(feed);
}
});
var isAccepted1 = collection.queryDocuments(
collection.getSelfLink(),
'SELECT base.FirstName, base.LastName FROM ContactPerson base where NOT IS_DEFINED(base.Address)',
function (err, feed1, options) {
console.log(222)
if (err) throw err;
if (!feed1|| !feed1.length) {
var response = getContext().getResponse();
response.setBody('no docs found');
}
else {
array.push(feed1);
}
});
var response = getContext().getResponse();
response.setBody(array);
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
You could adjust the format of output as you want.
You can simulate LEFT JOIN with the EXISTS sentence. Eg:
SELECT VALUE c
FROM c
WHERE (
--Like a "Left Join SomeCollection"
(NOT IS_DEFINED(c.SomeCollection) OR c.SomeCollection = null)
OR EXISTS (
SELECT null
FROM s IN c.SomeCollection
WHERE s.PropertyName = 'SomeValue'
)
)
--AND/OR Some other c Node conditions
then don't join. you can directly access the Address field. ex:
SELECT base.FirstName, base.LastName, Address.City FROM ContactPerson base
it will just display null or empty string if it has no property

How to use Convector to querie CouchDB Rich Queries with JSON Objects?

I'm here with a problem with rich queries and convector chaincodes, everything works with mango queries, but when I pass content object it's is stringifyed and don't will be sent has an object, but is converted to a string "content":"{\"data\":\"1971\"}", obvious it fails the query
original sample query
{
"selector": {
"type": "io.worldsibu.examples.person",
"attributes": {
"$elemMatch": {
"id": "born-year",
"content": {
"data": "1971"
}
}
}
}
}
graphql query variables
{
"getByAttributeInput": {
"id": "born-year",
"content": {
"data": "1971"
}
},
"skip": 0,
"take": 10
}
packages/person-cc/src/person.controller.ts
chaincode controller method
#Invokable()
public async getByAttribute(
#Param(yup.string())
id: string,
#Param(yup.mixed())
value: any
) {
return await Person.query(Person, {
selector: {
type: c.CONVECTOR_MODEL_PATH_PERSON,
attributes: {
$elemMatch: {
id: id,
content: value
}
}
}
});
}
in docker logs we can view that value is content is sent has a string and not a object ex "content":"{\"data\":\"1971\"}"
{"selector":{"type":"io.worldsibu.examples.person","attributes":{"$elemMatch":{"id":"born-year","content":"{\"data\":\"1971\"}"}}}}
the trick is change #Param(yup.mixed()) to #Param(yup.object()) and now it works has expected, we can query attributes content value with arbitrary and complex objects
#Invokable()
public async getByAttribute(
#Param(yup.string())
id: string,
// #Param(yup.mixed())
#Param(yup.object())
value: any
) {
...

query Azure Cosmos DB to return no duplicates

I have an Azure Cosmos DB with the following document below.
In this, the person with email jim#test.com has 3 roles, how can I query this to return a list comprising the email plus the 3 roles?
All I have just now is the following but that returns duplicate email addresses.
SELECT c.Email, o.RoleDesc
FROM c
JOIN o IN c.OrgRoles
WHERE c.Email = "jim#test.com"
{
"id": "23452345234",
"Email": "jim#test.com",
"OrgRoles": [
{
"RoleID": "234234",
"RoleDesc": "worker"
},
{
"RoleID": "345678",
"RoleDesc": "Manager"
},
{
"RoleID": "456433",
"RoleDesc": "Admin"
}
],
"DeviceIDs": [
{
"Device": "ABC-12312"
},
{
"Device": "DEF-76576"
}
],
"UpdatedDate": "01-12-17",
"CreatedDate": "01-11-17",
"_rid": "KFokAIrg-QABAAAAAAAAAA==",
"_self": "dbs/KFokAA==/colls/KFokAIrg-QA=/docs/KFokAIrg-QABAAAAAAAAAA==/",
"_etag": "\"00002d00-0000-0000-0000-59ef0f7f0000\"",
"_attachments": "attachments/",
"_ts": 1508839295
}
You need a user-defined function to do this. Register:
function getEmailAndRoles(doc) {
var result = { Email: doc.Email }
result.Roles = []
for(idx = 0; idx < doc.OrgRoles.length; idx++) {
result.Roles.push(doc.OrgRoles[idx].RoleDesc)
}
return result;
}
Then call
SELECT udf.getEmailAndRoles(c)
FROM c
WHERE c.Email = "jim#test.com"

Resources