Postgres query to return rows where json in the json column contains array elements more than one - sql

We are using Postgres DB , in that we have one table contains column of type JSON , format is like below
{
"name" : "XXX",
"id" : "123",
"course" :[
{
"name" : "java",
"tutor":"YYYY"
},
{
"name" : "python",
"tutor":"ZZZZ"
}
]
}
{
"name" : "XXX",
"id" : "123",
"course" :[
{
"name" : "java",
"tutor":"YYYY"
},
{
"name" : "python",
"tutor":"ZZZZ"
}
]
}
like this for example we have two rows , and in the json column we have each like above
i want to Postgre query , which will check the number of elements in the course array and if it is more than one , then only return that row
am not getting how to count the array elements from inside the json key
can any please suggest

why not just json_array_length?.. eg:
f=# with c(j) as (values('{
"name" : "XXX",
"id" : "123",
"course" :[
{
"name" : "java",
"tutor":"YYYY"
},
{
"name" : "python",
"tutor":"ZZZZ"
}
]
}'::json))
select json_array_length(j->'course') from c;
json_array_length
-------------------
2
(1 row)
so smth like
select * from table_name where json_array_length(j->'course') > 1

Related

How could I create indexes in postgres using jsonb?

I have a table in my database as follows
my_table:jsonb
[ {
"name" : "world map",
"type" : "activated",
"map" : [ {
"displayOrder" : 0,
"value" : 123
}, {
"displayOrder" : 1,
"value" : 456
}, {
"displayOrder" : 2,
"value" : 789
} ]
}, {
"name" : "regional map",
"type" : "disabled"
} ]
I would like to create indices for the name, type and displayOrder fields, which would be the best way?

DocumentDB SQL ARRAY_CONTAINS

In this case, the documents look like:
{
"id" : "1",
"Properties" : [
{
"Name" : "Leonard",
"Result" : "Pass",
"Grade" : "A"
},
{
"Name" : "Sheldon",
"Result" : "Pass",
"Grade" : "A"
},
{
"Name" : "Raj",
"Result" : "Fail",
"Grade" : "F"
},
{
"Name" : "Howard",
"Result" : "Pass",
"Grade" : "B"
}
]
}
I want to write a query which returns the elements with the "Result" : "Pass". I have tried ARRAY_CONTAINS() with query
SELECT * FROM d as c WHERE ARRAY_CONTAINS(c.Result, {"Result" : "Pass"}, true)
The Problem with the query is that it returns the whole of the array in as it is able to find "Result": "Pass" in the array. How should I modify or change the query such that the result contains only those elements of the array which has "Result": "Pass".
You just need to select the Properties
SELECT c.Properties[0] as Result
FROM c
JOIN tag IN c.Properties
WHERE tag.Result = "Pass"
Try this query which will return the id and only the matching items from the Properties array.
SELECT d.id, property
FROM d JOIN property IN d.properties
WHERE property.Result= "Pass"

Is it possible to use multiple json_object functions under one json_arrayagg function in Oracle?

I need to create JSON that has two sets of json objects under one array. These objects contain aggregated data from several tables. When I use json_arrayagg I get this error:
ORA-02000: missing ) keyword
The code should help explain more of what I've done and what I need.
SELECT JSON_OBJECT(
'rData' VALUE JSON_ARRAYAGG(
JSON_OBJECT(
'datapoints' VALUE JSON_ARRAY(JSON_OBJECT('key' VALUE 'ENM008137Q00190',
'value' VALUE tab3.column_6)),
'datatype' VALUE 'DATA_TYPE',
'id' VALUE tab1.column_4,
'key' VALUE tab3.column_1,
'timestamp' VALUE tab1.column_7),
JSON_OBJECT(
'id' VALUE tab1.column_4,
'key' VALUE tab3.column_1,
'timestamp' VALUE tab1.column_7,
'datatype' VALUE 'DATA_TYPE_2',
'datapoints' VALUE JSON_ARRAYAGG(JSON_OBJECT(
'key' VALUE tab5.column_8,
'value' VALUE tab2.column_9))))RETURNING CLOB)
FROM table_3 tab3,
table_4 tab4,
table_2 tab2,
table_1 tab1,
table_5 tab5
WHERE tab1.column_1 = tab2.column_1
AND tab3.column_2 = tab4.column_2
AND tab3.column_1 = tab2.column_1
AND tab1.column_1 = tab3.column_1
AND tab2.column_3 = tab5.column_3
AND tab2.latenttypeid = 1
AND tab3.column_2 = 2952326910
AND tab2.column_10 = 8878887
AND tab3.column_10 = 8878887
AND tab1.date BETWEEN '19-jun-19'
AND '25-jun-19'
GROUP BY tab1.column_4, tab3.column_1, tab3.column_6, tab1.column_7;
And here is the json output I would like:
{
"rData": [{
"datapoints": [
{"key" : "ENM008137Q00190","value" : "10"}
],
"datatype": "DATA_TYPE",
"id": "H2hnJikUKAhGVzslBVBHqg86DnwGhh8V",
"key": "534421188",
"timestamp": "2019-07-05T05:33:12.000Z"
},
{
"key":"534421188",
"id":"H2hnJikUKAhGVzslBVBHqg86DnwGhh8V" ,
"timestamp": "2019-07-05T05:33:12.000Z",
"datatype": "DATA_TYPE_2",
"datapoints": [
{"key" : "ENM008137L0001","value" : "56.0869029"},
{"key" : "ENM008137L0002","value" : "59.79244788"},
{"key" : "ENM008137L0003","value" : "73.34481183"},
{"key" : "ENM008137L0004","value" : "43.94661396"},
{"key" : "ENM008137L0005","value" : "80.71909567"},
{"key" : "ENM008137L0006","value" : "97.2707082"}
]
},{
"datapoints": [
{"key" : "ENM008137Q00190","value" : "9"}
],
"datatype": "DATA_TYPE",
"id": "A1JnnNjUKAhGVzslBVBHqg86Dnw52Ccj",
"key": "534421164",
"timestamp": "2019-07-05T04:27:45.000Z"
},
{
"key":"534421164",
"id":"A1JnnNjUKAhGVzslBVBHqg86Dnw52Ccj" ,
"timestamp": "2019-07-05T04:27:45.000Z",
"datatype": "DATA_TYPE_2",
"datapoints": [
{"key" : "ENM008137L0001","value" : "88.0869029"},
{"key" : "ENM008137L0002","value" : "88.79244788"},
{"key" : "ENM008137L0003","value" : "88.34481183"},
{"key" : "ENM008137L0004","value" : "82.94661396"},
{"key" : "ENM008137L0005","value" : "99.71909567"},
{"key" : "ENM008137L0006","value" : "88.2707082"}
]
}]
}
There are 2 json_objects under the "rData" array, these are the two data sources that I wanted aggregated, but I'm not sure if that's possible with the current functions.
I apologize for the code, I've tried to give you the least amount of info needed to help with this. And of course any help is always appreciated.

Remove Subdocument items with $pull

I'm trying to remove items from subdocuments using ExpressJS and Mongoose but it is only removing the first items, not the sub items.
So I want to remove "subitem 2" in the messages Array
This is the structure:
{
"_id" : ObjectId("5c4ee94b30ebd71cbed89a35"),
"title" : "Test",
"subitem" : [
{
"_id" : ObjectId("5c4ee95630ebd71cbed89a36"),
"title" : "Item 1",
"messages" : [
{
"_id" : ObjectId("5c4ee95f30ebd71cbed89a37"),
"type" : "single_article",
"date" : "Jan 28, 2019",
"title" : "subitem 1",
"text" : ""
}
]
},
{
"_id" : ObjectId("5c4ee96830ebd71cbed89a38"),
"title" : "item 2",
"messages" : [
{
"_id" : ObjectId("5c4ee96e30ebd71cbed89a39"),
"type" : "single_article",
"date" : "Jan 28, 2019",
"title" : "subitem 2",
"text" : ""
}
]
}
],
"__v" : 0
}
And this is the $pull method:
getController.deleteRec = function(req,res,collection){
var id = req.params.id;
console.log(id);
collection.updateOne({'subitem.messages._id': id}, {$pull: {'subitem.0.messages': {"_id": id}}}).
then(function(result){
console.log(result);
});
};
Now I know why it is only deleting the first item because I have "subitem.0.messages". How can I loop over this, so it can delete all items?
You can use $ as a wildcard index, removing all elements in the array matching your query like this:
{$pull: {'subitem.$.messages': {"_id": id}}}
if you want to remove multiple documents:
{$pull: {'subitem.$.messages': {"_id": {$in : [id, id2, id3...]}}}}

Mongodb aggregate with joins with multiple keys statement

Actually i am not trying to match two collection's . I am looking for match the field with secondary collection. I'll explain my problem clearly:
this is my primary collection "bags".which contains
{
"_id" : ObjectId("568f43e08a9f71b70b22a694"),
"bagNo" : "HBBN/00001/16",
"category" : "Voluntary",
"regNo" : "DNR/00001/16",
"status": "Accepted"
},
{ "_id" : ObjectId("568f4645fa0758af0e3fef26"), "bagNo" :"HBBN/00002/16", "category" : "Voluntary", "regNo" : "DNR/00002/16", "status": "Rejected" },
{ "_id" : ObjectId("568f4645fa4546gygfef26"), "bagNo" : "HBBN/00003/16", "category" : "Voluntary", "regNo" : "DNR/00003/16", "status": "Accepted" }
now my join collection "donor" contains
{"donorType" : "H",
"regNo" : "DNR/00001/16",
"surName" : "pandey",
"firstName" : "rakesh"},
{"donorType" : "C", "regNo" : "DNR/00002/16", "surName" : "pandey", "firstName" : "rakesh" },
{"donorType" : "C", "regNo" : "DNR/00003/16", "surName" : "pandey", "firstName" : "rakesh" }
from these two collections i want to get the accepted bags data from bags collection which having 'donortype' as 'H' in donor collection.Please let me know if it is possible.explain with some example
To combine two collections, you could try to do it with $lookup in aggregation.
donor.aggregation([
// filter the `donortype` of `H`
{$match: {donortype: 'H'}},
// join with `bags` collection for the foreign key `regNo`, and put bags into `h_bags` result.
{$lookup: {
from: "bags",
localField: "regNo",
foreignField: "regNo",
as: "h_bags"
}},
// unwind the `h_bags` array
{$unwind: '$h_bags'},
// filter the status of bags is `Accepted`
{$match: {'h_bags.status': 'Accepted'}}
]);