How to filter entities with nested arrays with CosmosDB - sql

I have an entity like this:
{
"id": "xxxx",
"attributes": [{
"name": "name-01",
"value": "value-01"
}, {
"name": "name-02",
"value": "value-02"
}
]
}
Our "questions" to data usually: Give me entities with attribute or attribute with particular value;
in SQL it was written like as:
select *
from c
where
and array_contains(c.attributes, { "name": "name-01", "value": "value-01" }, true)
and array_contains(c.attributes, { "name": "name-02", "value": "value-02" }, true)
but I would like to extend a model to allow have suggestion of values in each attribute by transform an entity to:
{
"id": "xxxx",
"attributes": [{
"name": "name_01",
"value": "value-01",
"suggestions": ["a", "b", "c"]
}, {
"name": "name_02",
"value": "value-02",
"suggestions": ["a", "d", "e"]
}
]
}
With that structure I would like to ask: Give me all entities that has specified attribute and value equals to "XYZ" or suggestions array contains "XYZ";
In general scenario if always add value into array of suggestions the ask would be "Give me all entities that has specified attribute and suggestions contains XYZ"
N.B. Also I would like to make queries : Give me all entities that has more ALL specified attributes with constraints per each by suggestions?
Please suggest how to write such queries or rebuild a structure of entities in Cosmos DB;
P.S. We can technically switch from SQL to other protocol to better make such queries;

This should be doable using ARRAY_CONTAINS along with iterating the attributes array.
Give me items with value "value-01" or suggestion "f":
SELECT DISTINCT VALUE(c)
FROM c JOIN attr IN c.attributes
WHERE attr["value"] = "value-01" OR ARRAY_CONTAINS(attr.suggestions, "f")
Give me items with value "value-01" or both suggestions "a" and "f":
SELECT DISTINCT VALUE(c)
FROM c JOIN attr IN c.attributes
WHERE attr["value"] = "value-01" OR
ARRAY_CONTAINS(attr.suggestions, "a") AND ARRAY_CONTAINS(attr.suggestions, "f")

Related

Change JSON Keys in Nested JSON in SQL Table

I have a table with column called tableJson which contains information of the following type:
[
{
"type": "TABLE",
"content": {
"rows":
[{"Date": "2021-09-28","Monthly return": "1.44%"},
{"Date": "2021-11-24", "Yearly return": "0.62%"},
{"Date": "2021-12-03", "Monthly return": "8.57%"},
{},
]
}
}
]
I want to change "Monthly Return" to "Weekly Return" everywhere in the table column where it exists.
Thank you in advance!
I tried different approaches to Parse, read, OPENJSON, CROSS APPLY but could not make it.

SQL - Extract values from key value pairs to array

I'm querying some data (SQL, presto), the source data has an array struct that includes a name and ID. I need to have an array of the IDs.
The data looks like:
[ { "id": 123456789,
"name": "name 1" },
{ "id": 234567891,
"name": "name 2" }
]
and I need it to look like:
[123456789, 234567891]
Do you know how I can achieve this?
It's: MAP_KEYS(MAP_FROM_ENTRIES(column))

Structures DB Schema Design

I am working on db schema for the below json. product has different parameterCategories and categories has different parameters. same parameter may belong to different categories. product can have 1 or more categories. product may have same categories with different parameters. let me know if my approach is correct. should I keep productCategory-section and section-parameters linking or simple table would work as I created below. all products of the same category will have same section and parameters so I am linking productCategory with parameters.
table Parameters
parameterid
parameterName
standard
value
parametersection
productCategory
{
"productCategory": "electronic",
"products": {
"productId": "productId",
"productName": "productName",
"productParameterSections": [
{
"productParameterSectionId": "appearance",
"parameters": [
{
"parameterId": "color",
"unit": "",
"standard": "red",
"val": "light red"
},
{
"parameterId": "brightness",
"unit": "",
"standard": "high",
"val": "medium"
}
]
},
{
"productParameterSectionId": "quantitative",
"parameters": [
{
"parameterId": "length",
"unit": "cm",
"standard": "440",
"val": "400"
},
{
"parameterId": "height",
"unit": "cm",
"standard": "red",
"val": "400"
}
]
}
]
}
}
Recently we work on the same schema design. What we did is as below:
Made a list of all the parameters possible and all the different fields in the parameters possible.
Then we created templates like here it is a category which is a combination of some of the parameters.
Then that template is assigned to any entity like product in this case.
Pros of this approach
- You can add as many parameters as you want in the list
- you can customize the template as you want and attach it to the entity
How to use it
Use parameters as a contact like an array of objects.
Create a template with an array of the selected parameters so that it is creating a copy of the selected parameter for every category to keep the constant array safe from updates.
The template is the second table which can have other fields like template name ( category name ) who created it when it is last updated even from which category it is created like a reference to own.
The final entity table ( product ) will have reference to that template table and also an array from that template. So reference provides information about parameters and you can update the copy with the values to use.
I hope it explains well, let me know if you still have any doubts.

PostgreSQL how to query jsonb by a value?

SELECT * FROM some_table;
I can query to get the following results:
{
"sku0": {
"Id": "18418",
"Desc": "yes"
},
"sku1": {
"Id": "17636",
"Desc": "no"
},
"sku2": {
"Id": "206714",
"Desc": "yes"
},
"brand": "abc",
"displayName": "something"
}
First, the number of skus is not fixed. It may be sku0, sku1, sku2, sku3, sku4 ... but they all start with sku.
Then, I want to query Id with 17636 and determine whether its value of Desc is yes or no. After reading the PostgreSQL JSON Functions and Operators documentation, Depressing I didn't find a good way.
I can convert the result into a Python dictionary, and then use python's method can easily achieve my requirements.
If the requirements can also be achieved with postgresql statements, which method is more recommended than the Python dictionary?
I am not sure I completely understand what the result is you want. But if you want to filter on the Id, you need to unnest all the elements inside the JSON column:
select d.v ->> 'Desc' as description
from the_table t
cross join jsonb_each(t.data) as d(k,v)
where d.v ->> 'Id' = '17636'
You could use the new jsonpath notation of PostgreSQL v12:
SELECT data ## '$.* ? (#.Id == "17636").Desc == "yes"'
FROM some_table;
That will start with the root of data ($), find any attribute in it (*), filter only those attributes that contain an Id with value "17636", get their Desc attribute and return TRUE only if that attribute is "yes".
Nice, isn't it?
This will probably give you what you need.
select value->>'Desc' from jsonb_each('{
"sku0": {
"Id": "18418",
"Desc": "yes"
},
"sku1": {
"Id": "17636",
"Desc": "no"
},
"sku2": {
"Id": "206714",
"Desc": "yes"
},
"brand": "abc",
"displayName": "something"
}'::jsonb)
where key like 'sku%'
and value->>'Id'='17636'
Best regards,
Bjarni

How to generate JSON array from multiple rows, then return with values of another table

I am trying to build a query which combines rows of one table into a JSON array, I then want that array to be part of the return.
I know how to do a simple query like
SELECT *
FROM public.template
WHERE id=1
And I have worked out how to produce the JSON array that I want
SELECT array_to_json(array_agg(to_json(fields)))
FROM (
SELECT id, name, format, data
FROM public.field
WHERE template_id = 1
) fields
However, I cannot work out how to combine the two, so that the result is a number of fields from public.template with the output of the second query being one of the returned fields.
I am using PostGreSQL 9.6.6
Edit, as requested more information, a definition of field and template tables and a sample of each queries output.
Currently, I have a JSONB row on the template table which I am using to store an array of fields, but I want to move fields to their own table so that I can more easily enforce a schema on them.
Template table contains:
id
name
data
organisation_id
But I would like to remove data and replace it with the field table which contains:
id
name
format
data
template_id
At the moment the output of the first query is:
{
"id": 1,
"name": "Test Template",
"data": [
{
"id": "1",
"data": null,
"name": "Assigned User",
"format": "String"
},
{
"id": "2",
"data": null,
"name": "Office",
"format": "String"
},
{
"id": "3",
"data": null,
"name": "Department",
"format": "String"
}
],
"id_organisation": 1
}
This output is what I would like to recreate using one query and both tables. The second query outputs this, but I do not know how to merge it into a single query:
[{
"id": 1,
"name": "Assigned User",
"format": "String",
"data": null
},{
"id": 2,
"name": "Office",
"format": "String",
"data": null
},{
"id": 3,
"name": "Department",
"format": "String",
"data": null
}]
The feature you're looking for is json concatenation. You can do that by using the operator ||. It's available since PostgreSQL 9.5
SELECT to_jsonb(template.*) || jsonb_build_object('data', (SELECT to_jsonb(field) WHERE template_id = templates.id)) FROM template
Sorry for poorly phrasing what I was trying to achieve, after hours of Googling I have worked it out and it was a lot more simple than I thought in my ignorance.
SELECT id, name, data
FROM public.template, (
SELECT array_to_json(array_agg(to_json(fields)))
FROM (
SELECT id, name, format, data
FROM public.field
WHERE template_id = 1
) fields
) as data
WHERE id = 1
I wanted the result of the subquery to be a column in the ouput rather than compiling the entire output table as a JSON.