$unwind multiple arrays present in the embedded documents and show each array as single document as output in mongoDB - arrays

Refer below code. In this, field scenario is a embedded document which has has arrays and I want to showcase each array as a single document in the output. Note that each array contains embedded document in it so it would be helpful to get the code which extracts fields from those too. I'm not using java to query. Would be using external BI application which would be integrated in. Think I should also mention that i'm using NoSQLBooster for MongoDB application to create these queries.
{
"_id": {
"$oid": ""
},
"organisationId": "",
"bcpId": "",
"bcpName": "",
"bcpDescription": "",
"biaEntity": {},
"version": "0.01",
"status": "PENDING",
"primaryBridgeNumber": "1",
"alternateBridgeNumber": "2",
"scenario": [{
"_id": {
"$oid": "5e3ab709367d2c5f5826c6fd"
},
"scenario": "",
"strategies": [{
"mdmStrategy": {},
"strategy": {
"pSIStrategyDetails": {
"scenarioName": "",
"strategyName": "",
"rto": "",
"sustainablePeriod": {
},
"description": "1",
"primaryContact": {
},
"secondaryContact": {
},
"recoverySite": {
}
},
"pSICriticalStaff": {},
"specialRequirement": [{
}, {
}, {
}, {
}, {
}]
},
"createdOn": {},
"updatedOn": {}
}, {
"mdmStrategy": {},
"strategy": {
"pSIStrategyDetails": {},
"pSICriticalStaff": {},
"specialRequirement": [{
},
{
},
{
},
{
},
{
}]
},
"createdOn": {},
"updatedOn": }
}],
"description": "",
"status": "Active",
"createdOn": {},
"updatedOn": {}
}],
"updatedOn": {},
"createdOn": {},
"business_owner_id": {},
"bc_coordinator_id": {},
"backup_business_owner_id": {},
"backup_business_coordinator_id": {},
"sme_id": {},
"_class": "com.bcm.bcp.api.model.BcmBcpEntity"
}
expected output:
{{
"bcpId": "",
"bcpName": "",
"bcpDescription": "",
"version": "0.01",
"status": "PENDING",
"scenario.scenario":"---",
"scenario.strategies.strategy.strategyName":"---",
"scenario.strategies.strategy.rto":"---",
etc...
}{
"bcpId": "",
"bcpName": "",
"bcpDescription": "",
"version": "0.01",
"status": "PENDING",
"scenario.scenario":"---",
"scenario.strategies.strategy.strategyName":"---",
"scenario.strategies.strategy.rto":"---",
etc...
}{
"bcpId": "",
"bcpName": "",
"bcpDescription": "",
"version": "0.01",
"status": "PENDING",
"scenario.scenario":"---",
"scenario.strategies.strategy.strategyName":"---",
"scenario.strategies.strategy.rto":"---",
etc...
}}
"scenario.scenario":"---","scenario.strategies.strategy.strategyName":"---",
"scenario.strategies.strategy.rto":"---",
will be coming from the arrays so the output will be number of elements present in the array

U hope this is what you want:
db.collection.aggregate([
{
$unwind: "$scenario"
},
{
$unwind: "$scenario.strategies"
},
{
$project: {
bcpId: 1,
bcpName: 1,
bcpDescription: 1,
version: 1,
status: 1,
scenario: {
scenario: 1,
strategies: {
strategy: {
pSIStrategyDetails: {
rto: 1,
strategyName: 1
}
}
}
}
}
}
])
Output:
[
{
"_id": ObjectId("5a934e000102030405000000"),
"bcpDescription": "",
"bcpId": "",
"bcpName": "",
"scenario": {
"scenario": "",
"strategies": {
"strategy": {
"pSIStrategyDetails": {
"rto": "",
"strategyName": ""
}
}
}
},
"status": "PENDING",
"version": "0.01"
},
{
"_id": ObjectId("5a934e000102030405000000"),
"bcpDescription": "",
"bcpId": "",
"bcpName": "",
"scenario": {
"scenario": "",
"strategies": {
"strategy": {
"pSIStrategyDetails": {}
}
}
},
"status": "PENDING",
"version": "0.01"
}
]
Explanation: You need to use 2 $unwind operators, as it is like arrays of arrays and a $project operator to display only those fields, which you need.
MongoPlayGroundLink
P.S. - The question is still unclear.

Related

Adding elements within Object TypeScript

Hello everyone i have dynamically expanding object which consists of a 2 x dimensional array. I
try to add in field label:{ } new key:value {"hg":"Hg"} object.
object JSON:
[
{
"callbackQueryData": "tNLQy3VcX",
"method": {
"value": "",
"property": "",
"linkUrl": "",
"inside": null,
"type": "NEXT_PAGE",
"nextId": "Cll8xZbVo6",
"validation": null,
"calendar": null,
"condition": null,
"api": null,
"pagination": null
},
"label": {
"en": "New button"
}
},
{
"callbackQueryData": "qntufUVhz",
"label": {
"en": "New button"
},
"method": {
"value": "",
"property": "",
"linkUrl": "",
"inside": null,
"type": "NEXT_PAGE",
"nextId": "",
"validation": null,
"calendar": null,
"condition": null,
"api": null,
"pagination": null
}
}
],
[
{
"callbackQueryData": "cx46ECYG9",
"label": {
"en": "New button"
},
"method": {
"value": "",
"property": "",
"linkUrl": "",
"inside": null,
"type": "NEXT_PAGE",
"nextId": "",
"validation": null,
"calendar": null,
"condition": null,
"api": null,
"pagination": null
}
}
],
[
{
"callbackQueryData": "uHp5yd3Li",
"label": {
"en": "New button"
},
"method": {
"value": "",
"property": "",
"linkUrl": "",
"inside": null,
"type": "NEXT_PAGE",
"nextId": "",
"validation": null,
"calendar": null,
"condition": null,
"api": null,
"pagination": null
}
}
],
[]
]
I try cast it to simple array and via forEach() addressing everyone elements button:any and to add object which i need. But Spread syntax(...) can't find argument forEach().Or I'm doing it completely wrong.
let arrayButton:IBotButton[][] = ([] as IBotButton[][]).concat(...page.callbacks)//create simple array
arrayButton.forEach((button:any)=>{
...button,
label: { ...button.label, [languageSelect]: buttonText }
})
Assume your arrayButton looks like this:
const arrayButton: IBotButton[][] = [
[
{
label: { "en": "new Button-1" }
// ...
},
{
label: { "en": "new Button-2" }
// ...
},
//...
],
[
//...
]
];
And have these variables:
const languageSelect: string = "jp";
const buttonText: string = "new Button-3";
Then you could modify the label by following code:
// arrayButton is 2d array
arrayButton.forEach((array) => {
// array is 1d array
array.forEach((button, buttonIdx) => {
array[buttonIdx] = {
...button,
label: {
...button.label,
[languageSelect]: buttonText,
},
};
});
});

how can i listing component nestedly?

[
{
"id": 0.5256669517010202,
"color": false,
"selected": false,
"name": "",
"type": "",
"label": "",
"fieldName": "",
"required": "",
"validation": ""
},
{
"id": 0.5901705709044824,
"color": false,
"selected": false,
"type": [
{
"id": 0.30332161644408817,
"color": true,
"selected": false,
"name": "",
"type": "",
"label": "",
"fieldName": "",
"required": "",
"validation": ""
},
{
"id": 0.5423422175390649,
"color": true,
"selected": false,
"name": "",
"type": "",
"label": "",
"fieldName": "",
"required": "",
"validation": ""
},
{
"id": 0.959208393000617,
"color": true,
"selected": false,
"name": "",
"type": "",
"label": "",
"fieldName": "",
"required": "",
"validation": ""
}
],
"label": "",
"fieldName": "",
"required": "",
"validation": ""
},
{
"id": 0.5933110602496239,
"color": false,
"selected": false,
"type": "",
"label": "",
"fieldName": "",
"required": "",
"validation": ""
}
]
I think you should use Map method
const data = [
{
"id": 0.5256669517010202,
"color": false,
"selected": false,
"name": "",
"type": "",
"label": "",
"fieldName": "",
"required": "",
"validation": ""
},
{
"id": 0.5901705709044824,
"color": false,
"selected": false,
"type": [
{
"id": 0.30332161644408817,
"color": true,
"selected": false,
"name": "",
"type": "",
"label": "",
"fieldName": "",
"required": "",
"validation": ""
},
{
"id": 0.5423422175390649,
"color": true,
"selected": false,
"name": "",
"type": "",
"label": "",
"fieldName": "",
"required": "",
"validation": ""
},
{
"id": 0.959208393000617,
"color": true,
"selected": false,
"name": "",
"type": "",
"label": "",
"fieldName": "",
"required": "",
"validation": ""
}
],
"label": "",
"fieldName": "",
"required": "",
"validation": ""
},
{
"id": 0.5933110602496239,
"color": false,
"selected": false,
"type": "",
"label": "",
"fieldName": "",
"required": "",
"validation": ""
}
]
data.map((item) => item.id)
Just Try!
You should declared attribute type as Array always!
data.map(Item => (
Item.type.map(Item => ())
))
the map method is suitable here. For example you have your all data within state or another variable, well you can map throw it:
<div>
{yourData?.length && yourData.map(item => {
return(
<span>{item.id}</span>
...
<div>{item.type.map(typeItem => {
return(
<span>{typeItem.id}</span>
...
)
})
)})}
</div>

How to parse complex data using react native?

Following is the DATA that needs to parse which can nested arrays and objects i need
help understanding the easiest way to parse this .
const country= [
{
"place": "sikkim",
"location": 2,
"Extension": "",
"Keys": {
"string": [
"Enabled",
"Disabled"
]
},
"ItemValues": {
"ItemData": [
{
"Name": "Enabled",
"Data": {
"Rows": {
"Row": {
"Values": {
"Type": false
}
}
}
}
},
{
"Name": "Value",
"Data": {
"Rows": {
"DataRow": {
"Values": {
"anyType": "100"
}
}
}
}
}
]
}
},
{
"place": "assam",
"location": 1,
"Extension": "",
"Keys": {
"string": "MinValue"
},
"ItemValues": {
"ItemData": {
"Name": "nValue",
"Data": {
"Rows": {
"DataRow": {
"Values": {
"anyType": "1"
}
}
}
}
}
}
}
]
In this array 2 objects are there i need to parse this complex array of object and
show like this -
OUTCOME should be -
sikkim:{
"place": "sikkim",
"location": 2,
"Extension": "",
"string":"Enabled","Disabled",
"Name": "Enabled",
"Type": false,
"Name": "Value",
"anyType": 100
},
assam:{.. so on}
code that i tried is displaying only keys -
const getValues = country =>
country === Object(country)
? Object.values(country).flatMap(getValues)
: [country];
console.log(getValues(country));
OUTPUT from above code =
 ["sikkim", 2, "", "Enabled", "Disabled", "Enabled", false, "Value", "100",
"assam", 1, "", "MinValue", "nValue", "1"]
Need to write logic which is smart way to write to cover this logic because my data
is huge any leads?I can achieve the output but writing many for and if loops but that
creates lot of confusion.

Listing Nested JSON Objects

We have the following JSON structure from an TSheets API which has an actual timesheet 'id' as an object in the hierarchy. This means there's no fixed hierarchy structure and we need to dynamically find a way to loop through each timesheet.
We've stored this data in a variant column, but want to flatten it and have a row per timesheet. Is there a way to list all objects under results.timesheets to retrieve all ids in a single column (i.e. '13510958','13510960') so we can loop through these to obtain the lower level details. Seems like an odd way to construct an API response!
JSON can be found below:
{
"results": {
"timesheets": {
"13510958": {
"id": 13510958,
"user_id": 1360082,
"jobcode_id": 16297998,
"start": "",
"end": "",
"duration": 28800,
"date": "2021-03-29",
"tz": 1,
"tz_str": "Europe/London",
"type": "manual",
"location": "QuickBooks Time web",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"802478": "",
"650642": "",
"650640": "Consulting Services:Services"
},
"last_modified": "2021-04-19T14:34:16+00:00",
"attached_files": [],
"created_by_user_id": 1360067
},
"13510960": {
"id": 13510960,
"user_id": 1360082,
"jobcode_id": 16297998,
"start": "",
"end": "",
"duration": 28800,
"date": "2021-03-30",
"tz": 1,
"tz_str": "Europe/London",
"type": "manual",
"location": "QuickBooks Time web",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"802478": "",
"650642": "",
"650640": "Consulting Services:Services"
},
"last_modified": "2021-04-19T14:34:16+00:00",
"attached_files": [],
"created_by_user_id": 1360067
}}
} }
You can use LATERL FLATTEN, LISTAGG or ARRAY_AGG to get it:
with json_data as ( select parse_json('{
"results": {
"timesheets": {
"13510958": {
"id": 13510958,
"user_id": 1360082,
"jobcode_id": 16297998,
"start": "",
"end": "",
"duration": 28800,
"date": "2021-03-29",
"tz": 1,
"tz_str": "Europe/London",
"type": "manual",
"location": "QuickBooks Time web",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"802478": "",
"650642": "",
"650640": "Consulting Services:Services"
},
"last_modified": "2021-04-19T14:34:16+00:00",
"attached_files": [],
"created_by_user_id": 1360067
},
"13510960": {
"id": 13510960,
"user_id": 1360082,
"jobcode_id": 16297998,
"start": "",
"end": "",
"duration": 28800,
"date": "2021-03-30",
"tz": 1,
"tz_str": "Europe/London",
"type": "manual",
"location": "QuickBooks Time web",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"802478": "",
"650642": "",
"650640": "Consulting Services:Services"
},
"last_modified": "2021-04-19T14:34:16+00:00",
"attached_files": [],
"created_by_user_id": 1360067
}}
}}') raw )
select listagg( v.key , ',' ), array_agg( v.key)
from json_data,
lateral flatten( raw:results.timesheets ) v;
When you want to obtain the lower level details without looping through them, you can also access them directly. For example the timesheet, user_id and duration:
with json_data as (
select parse_json('{
"results": {
"timesheets": {
"13510958": {
"id": 13510958,
"user_id": 1360082,
"jobcode_id": 16297998,
"start": "",
"end": "",
"duration": 28800,
"date": "2021-03-29",
"tz": 1,
"tz_str": "Europe/London",
"type": "manual",
"location": "QuickBooks Time web",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"802478": "",
"650642": "",
"650640": "Consulting Services:Services"
},
"last_modified": "2021-04-19T14:34:16+00:00",
"attached_files": [],
"created_by_user_id": 1360067
},
"13510960": {
"id": 13510960,
"user_id": 1360082,
"jobcode_id": 16297998,
"start": "",
"end": "",
"duration": 28800,
"date": "2021-03-30",
"tz": 1,
"tz_str": "Europe/London",
"type": "manual",
"location": "QuickBooks Time web",
"on_the_clock": false,
"locked": 0,
"notes": "",
"customfields": {
"802478": "",
"650642": "",
"650640": "Consulting Services:Services"
},
"last_modified": "2021-04-19T14:34:16+00:00",
"attached_files": [],
"created_by_user_id": 1360067
}}
}}') raw )
select key, value:user_id, value:duration
from json_data,
lateral flatten(input=>raw:results.timesheets)
I was able to get this to work.
SELECT VALUE AS TIMESHEET_JSON, TIMESHEET_JSON:id AS ID
FROM TABLE(FLATTEN(INPUT=> PARSE_JSON('{Your JSON Here}'):results.timesheets));
You may need to do a little more work to get your JSON into the flatten. A lateral flatten may be useful. This worked once I put your JSON into a one column cte.
SELECT VALUE AS TIMESHEET_JSON, TIMESHEET_JSON:id AS ID
FROM cte
,LATERAL FLATTEN(INPUT=> PARSE_JSON(JSON):results.timesheets);
You can then use typical JSON parsing syntax against the VALUE column for getting at your individual attributes per record.

Snowflake - how do I retrieve the name of the currently executing procedure?

I'd like to access the name of the currently executing procedure in Snowflake in the javascript procedure itself and store it in a variable.
When I interrogate the "this" object, I can see the name in the Variant return, but in terms of JSON I believe it's the name not the value and I'm not sure how to retrieve the first name in the JSON object.
What code do I need to use to get the procedure name?
procName = ???what code goes here with the this object???;
Do we know that the first name/value pair in "this" will always be the procedure name?
CREATE OR REPLACE PROCEDURE EDW_ADMIN.DAG_TEST()
RETURNS VARIANT
LANGUAGE JAVASCRIPT
AS
$$
var procName = "";
// procName = this.??? WHAT DO I PUT HERE ???
return this;
$$
;
The return / contents of "this" are:
{
"DAG_TEST": {},
"ResultSet": {},
"SfTimestamp": {},
"Snowflake": {},
"Statement": {},
"Status": {
"EOF": "eof",
"ERROR": "error",
"INITIALIZED": "initialized",
"SUCCESS": "success"
},
"_c_snowflake": {
"createExecError": {},
"createStatement": {}
},
"createError": {},
"extractValue": {},
"getColSqlTypeFromIdx": {},
"nativeTypes": {
"values": {
"BOOLEAN": "boolean",
"BUFFER": "buffer",
"DATE": "date",
"INVALID": "invalid",
"JSON": "json",
"NUMBER": "number",
"STRING": "string"
}
},
"noSuchColumnIdxErrorMessage": "Given column name/index does not exist: ",
"snowflake": {
"createStatement": {},
"execute": {}
},
"sqlTypeFromLibSfDbTypeVal": {},
"sqlTypes": {
"isArray": {},
"isBinary": {},
"isBoolean": {},
"isDate": {},
"isNumber": {},
"isObject": {},
"isText": {},
"isTime": {},
"isTimestamp": {},
"isTimestampLtz": {},
"isTimestampNtz": {},
"isTimestampTz": {},
"isVariant": {},
"values": {
"ARRAY": {
"libSfDbType": 9,
"name": "ARRAY"
},
"BINARY": {
"libSfDbType": 10,
"name": "BINARY"
},
"BOOLEAN": {
"libSfDbType": 12,
"name": "BOOLEAN"
},
"DATE": {
"libSfDbType": 3,
"name": "DATE"
},
"FIXED": {
"libSfDbType": 0,
"name": "FIXED"
},
"INVALID_SQL_TYPE": {
"libSfDbType": -1,
"name": "INVALID_SQL_TYPE"
},
"OBJECT": {
"libSfDbType": 8,
"name": "OBJECT"
},
"REAL": {
"libSfDbType": 1,
"name": "REAL"
},
"TEXT": {
"libSfDbType": 2,
"name": "TEXT"
},
"TIME": {
"libSfDbType": 11,
"name": "TIME"
},
"TIMESTAMP_LTZ": {
"libSfDbType": 4,
"name": "TIMESTAMP_LTZ"
},
"TIMESTAMP_NTZ": {
"libSfDbType": 5,
"name": "TIMESTAMP_NTZ"
},
"TIMESTAMP_TZ": {
"libSfDbType": 6,
"name": "TIMESTAMP_TZ"
},
"VARIANT": {
"libSfDbType": 7,
"name": "VARIANT"
}
}
},
"testFunc": {},
"typeFromLibSfDbTypeVal": {},
"validateBinds": {},
"validateColumnExists": {}
}
Try this in your proc:
const procName = Object.keys(this)[0];
Assuming that the procName is always the first key in the dictionary! Also using const wherever possible is a good practice.
Try CURRENT_STATEMENT(); haven't tested, so let us know

Resources