I have JSON that looks like this
const err = [
{
"Error": Name Not Valid",
"Content": [
{
"Name": "Johnz"
}
]
},
{
"Error": "Data Not Valid",
"Content": [
{
"Investor": "3785388",
"ManagedBy": "Johnz"
},
{
"Investor": "1111111",
"ManagedBy": "Mary"
}
]
}]
How can I set it so it looks like this? I need to move anything that appears in the content array to the main structure where title is.
const err= [
{
"Error": "Name Not Valid",
"Name": "Johnz"
},
{
"Error": "Data Not Valid",
"Investor": "3785388",
"ManagedBy": "Johnz"
},
{
"Error": "Data Not Valid"
"Investor": "1111111",
"ManagedBy": "Mary"
}]
It helps if you define a minimal type for the err variable.
An option then would be:
const err: { Error: string, Content: any[] }[] = [
{
"Error": "Name Not Valid",
"Content": [
{
"Name": "Johnz"
}
]
},
{
"Error": "Data Not Valid",
"Content": [
{
"Investor": "3785388",
"ManagedBy": "Johnz"
},
{
"Investor": "1111111",
"ManagedBy": "Mary"
}
]
}];
const flattenedError = err.map(error => {
const flattened = { error: error.Error };
return error.Content.reduce((acc, curent) => {
Object.keys(curent).forEach((key) => {
acc[key] = curent[key];
});
return acc;
}, flattened);
});
A working example can be found here.
Related
I use a script that runs a Nest thermostat. It works well for me, but when I share it with another person with multiple thermostats, it does not work even though I set up the script to run only on one of his thermostats.
This is the script I am talking about:
function changetemp() {
// enter the thermostat ID manually after running makerequesttest function
const THERMOSTAT = '';
const smartService = getSmartService();
const access_token = smartService.getAccessToken();
const url = 'https://smartdevicemanagement.googleapis.com/v1';
const endpoint = '/enterprises/' + PROJECT_ID + '/devices';
const headers = {
'Authorization': 'Bearer ' + access_token,
'Content-Type': 'application/json'
}
const params = {
'headers': headers,
'method': 'get',
'muteHttpExceptions': true
}
try {
const response = UrlFetchApp.fetch(url + endpoint, params);
const responseCode = response.getResponseCode();
const responseBody = JSON.parse(response.getContentText());
console.log("Response code: " + responseCode);
console.log(responseBody);
const devices = responseBody['devices'];
const device = devices.find(d => d.name === 'enterprises/' + PROJECT_ID + '/devices/' + THERMOSTAT)
if (!device) {
console.log("Thermostat with ID " + THERMOSTAT + " not found.")
return
}
}
The person with multiple thermostats gets the "not found" message, while it works for me.
The THERMOSTAT const is gotten from that function that we execute first:
function makeRequesttest() {
// get the smart service
const smartService = getSmartService();
// get the access token
const access_token = smartService.getAccessToken();
//console.log(access_token);
// setup the SMD API url
const url = 'https://smartdevicemanagement.googleapis.com/v1';
const endpoint = '/enterprises/' + PROJECT_ID + '/devices';
// setup the headers for the call
const headers = {
'Authorization': 'Bearer ' + access_token,
'Content-Type': 'application/json'
}
// set up params
const params = {
'headers': headers,
'method': 'get',
'muteHttpExceptions': true
}
// try calling API
try {
const response = UrlFetchApp.fetch(url + endpoint, params);
const responseBody = JSON.parse(response.getContentText());
Logger.log('response: ' + response);
return responseBody;
}
catch(e) {
console.log('Error: ' + e);
//throw e;
}
}
The makeRequesttest() function gives me that result:
response: {
"devices": [
{
"name": "enterprises/AAA/devices/BBB",
"type": "sdm.devices.types.THERMOSTAT",
"assignee": "enterprises/AAA/structures/CCC/rooms/DDD",
"traits": {
"sdm.devices.traits.Info": {
"customName": ""
},
"sdm.devices.traits.Humidity": {
"ambientHumidityPercent": 58
},
"sdm.devices.traits.Connectivity": {
"status": "ONLINE"
},
"sdm.devices.traits.Fan": {},
"sdm.devices.traits.ThermostatMode": {
"mode": "OFF",
"availableModes": [
"HEAT",
"OFF"
]
},
"sdm.devices.traits.ThermostatEco": {
"availableModes": [
"OFF",
"MANUAL_ECO"
],
"mode": "OFF",
"heatCelsius": 13.04544,
"coolCelsius": 24.44443
},
"sdm.devices.traits.ThermostatHvac": {
"status": "OFF"
},
"sdm.devices.traits.Settings": {
"temperatureScale": "CELSIUS"
},
"sdm.devices.traits.ThermostatTemperatureSetpoint": {},
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 9.20999
}
},
"parentRelations": [
{
"parent": "enterprises/AAA/structures/EEE/rooms/FFF",
"displayName": "Office"
}
]
}
]
}
With that log, I manually update the THERMOSTAT const value.
The person with multiple thermostats gets that result with makeRequestest():
Logging output too large. Truncating output. response: {
"devices": [
{
"name": "enterprises/XXX/devices/AVPHwGGG",
"type": "sdm.devices.types.THERMOSTAT",
"assignee": "enterprises/XXX/structures/YYY/rooms/ZZZ",
"traits": {
"sdm.devices.traits.Info": {
"customName": ""
},
"sdm.devices.traits.Humidity": {
"ambientHumidityPercent": 28
},
"sdm.devices.traits.Connectivity": {
"status": "ONLINE"
},
"sdm.devices.traits.Fan": {},
"sdm.devices.traits.ThermostatMode": {
"mode": "HEAT",
"availableModes": [
"HEAT",
"OFF"
]
},
"sdm.devices.traits.ThermostatEco": {
"availableModes": [
"OFF",
"MANUAL_ECO"
],
"mode": "OFF",
"heatCelsius": 16.52971,
"coolCelsius": 24.44444
},
"sdm.devices.traits.ThermostatHvac": {
"status": "OFF"
},
"sdm.devices.traits.Settings": {
"temperatureScale": "FAHRENHEIT"
},
"sdm.devices.traits.ThermostatTemperatureSetpoint": {
"heatCelsius": 17.777779
},
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 19.17
}
},
"parentRelations": [
{
"parent": "enterprises/XXX/structures/YYY/rooms/ZZZ",
"displayName": "Notinteresting1"
}
]
},
{
"name": "enterprises/XXX/devices/AVPHAAA",
"type": "sdm.devices.types.THERMOSTAT",
"assignee": "enterprises/XXX/structures/YYY/rooms/BBB",
"traits": {
"sdm.devices.traits.Info": {
"customName": ""
},
"sdm.devices.traits.Humidity": {
"ambientHumidityPercent": 27
},
"sdm.devices.traits.Connectivity": {
"status": "ONLINE"
},
"sdm.devices.traits.Fan": {},
"sdm.devices.traits.ThermostatMode": {
"mode": "HEAT",
"availableModes": [
"HEAT",
"OFF"
]
},
"sdm.devices.traits.ThermostatEco": {
"availableModes": [
"OFF",
"MANUAL_ECO"
],
"mode": "OFF",
"heatCelsius": 12.77776,
"coolCelsius": 24.44444
},
"sdm.devices.traits.ThermostatHvac": {
"status": "HEATING"
},
"sdm.devices.traits.Settings": {
"temperatureScale": "FAHRENHEIT"
},
"sdm.devices.traits.ThermostatTemperatureSetpoint": {
"heatCelsius": 18.98769
},
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 19.03
}
},
"parentRelations": [
{
"parent": "enterprises/XXX/structures/YYY/rooms/BBB",
"displayName": "Notinteresting2"
}
]
},
{
"name": "enterprises/XXX/devices/CCC",
"type": "sdm.devices.types.THERMOSTAT",
"assignee": "enterprises/XXX/structures/YYY/rooms/DDD",
"traits": {
"sdm.devices.traits.Info": {
"customName": ""
},
"sdm.devices.traits.Humidity": {
"ambientHumidityPercent": 29
},
"sdm.devices.traits.Connectivity": {
"status": "ONLINE"
},
"sdm.devices.traits.Fan": {},
"sdm.devices.traits.ThermostatMode": {
"mode": "HEAT",
"availableModes": [
"HEAT",
"OFF"
]
},
"sdm.devices.traits.ThermostatEco": {
"availableModes": [
"OFF",
"MANUAL_ECO"
],
"mode": "OFF",
"heatCelsius": 17.062832,
"coolCelsius": 24.44444
},
"sdm.devices.traits.ThermostatHvac": {
"status": "OFF"
},
"sdm.devices.traits.Settings": {
"temperatureScale": "FAHRENHEIT"
},
"sdm.devices.traits.ThermostatTemperatureSetpoint": {
"heatCelsius": 16.71161
},
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 19.67999
}
},
"parentRelations": [
{
"parent": "enterprises/XXX/structures/YYY/rooms/DDD",
"displayName": "Theone"
}
]
},
{
"name": "enterprises/XXX/devices/EEE",
"type": "sdm.devices.types.THERMOSTAT",
"assignee": "enterprises/XXX/structures/YYY/rooms/FFF",
"traits": {
"sdm.devices.traits.Info": {
"customName": ""
},
"sdm.devices.traits.Humidity": {
"ambientHumidityPercent": 26
},
"sdm.devices.traits.Connectivity": {
"status": "ONLINE"
},
"sdm.devices.traits.Fan": {},
"sdm.devices.traits.ThermostatMode": {
"mode": "HEAT",
"availableModes": [
"HEAT",
"OFF"
]
},
"sdm.devices.traits.ThermostatEco": {
"availableModes": [
"OFF",
"MANUAL_ECO"
],
"mode": "OFF",
"heatCelsius": 15.586624,
"coolCelsius": 24.444443
},
"sdm.devices.traits.ThermostatHvac": {
"status": "OFF"
},
"sdm.devices.traits.Settings": {
"temperatureScale": "FAHRENHEIT"
},
"sdm.devices.traits.ThermostatTemperatureSetpoint": {
"heatCelsius": 18.360092
},
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 19.259995
}
},
"parentRelations": [
{
"parent": "enterprises/XXX/structures/YYY/rooms/AVPHw
The thermostat with display name "Theone" is the one that we are interested in.
We updated the THERMOSTAT const manually with "CCC" in the changetemp function. And we tried with other values he got like "GGG" or "DDD" but still got the log "device not found".
For that reason, I decided to create a "dummy" device in Google Cloud Console in order to simulate the fact that I have many thermostats running.
What is the way to acces this thermostat from Google Apps Script? How to make my script run like this fake device exists in my installation?
This is what I have at the moment in my registry:
dummydevice-details
dummydevice-configstate
dummydevice-authentication
Edit: public key added to the device:
dummydevice-authenticationpublickey
I need to merge file1.json file2.json (could be more) into onefile.json.
version is always the same value in all files. however vulnerabilities array and dependency_files array values different but there might be duplicate/which I want to remove if any after the merge
file1.json:
{
"version": "x.x.x",
"vulnerabilities": [
{
"id": "0000"
},
{
"id": "11111"
},
{
"id": "2222"
}
],
"dependency_files": [
{
"name": "name0000"
},
{
"name": "name1111"
},
{
"name": "name2222"
}
]
}
file2.json:
{
"version": "x.x.x",
"vulnerabilities": [
{
"id": "2222"
},
{
"id": "3333"
}
],
"dependency_files": [
{
"name": "name2222"
},
{
"name": "name3333"
}
]
}
onefile.json:
{
"version": "x.x.x",
"vulnerabilities": [
{
"id": "0000"
},
{
"id": "11111"
},
{
"id": "2222"
},
{
"id": "3333"
}
],
"dependency_files": [
{
"name": "name0000"
},
{
"name": "name1111"
},
{
"name": "name2222"
},
{
"name": "name3333"
}
]
}
I tried a lot with no luck
You could have a reduce on all files, initialized with the first, hence no need for the -n option:
jq '
reduce inputs as {$vulnerabilities, $dependency_files} (.;
.vulnerabilities = (.vulnerabilities + $vulnerabilities | unique_by(.id))
| .dependency_files = (.dependency_files + $dependency_files | unique_by(.name))
)
' file*.json
{
"version": "x.x.x",
"vulnerabilities": [
{
"id": "0000"
},
{
"id": "11111"
},
{
"id": "2222"
},
{
"id": "3333"
}
],
"dependency_files": [
{
"name": "name0000"
},
{
"name": "name1111"
},
{
"name": "name2222"
},
{
"name": "name3333"
}
]
}
Demo
Using this python code
import json
def merge_dicts(*dicts):
r = {}
skip = 'version'
for item in dicts:
for key, value in item.items():
if (key == skip):
r[skip] = value
else:
r.setdefault(key, []).extend(value)
unique = []
for obj in r[key]:
if obj not in unique:
unique.append(obj)
r[key] = unique
return r
with open("file1.json") as file_1:
data_1 = json.load(file_1)
with open("file2.json") as file_2:
data_2 = json.load(file_2)
with open('data.json', 'w') as merge_file:
json.dump(merge_dicts(data_1, data_2), merge_file, indent = 4)
Result
{
"version": "x.x.x",
"vulnerabilities": [
{
"id": "0000"
},
{
"id": "11111"
},
{
"id": "2222"
},
{
"id": "3333"
}
],
"dependency_files": [
{
"name": "name0000"
},
{
"name": "name1111"
},
{
"name": "name2222"
},
{
"name": "name3333"
}
]
}
This code is multiple json files support
import os, json
def merge_dicts(*dicts):
r = {}
skip = 'version'
for item in dicts:
for key, value in item.items():
if (key == skip):
r[skip] = value
else:
r.setdefault(key, []).extend(value)
unique = []
for obj in r[key]:
if obj not in unique:
unique.append(obj)
r[key] = unique
return r
json_files = [pos_json for pos_json in os.listdir('./') if pos_json.endswith('.json')]
a = []
print(type(a))
for json_file in json_files:
with open(json_file) as file_item:
read_data = json.load(file_item)
a.append(read_data)
file_item.close()
with open('data.json', 'w') as merge_file:
json.dump(merge_dicts(*tuple(a)), merge_file, indent = 4)
After first system call fails, i am getting this json.
{
"header": {
"msgCode": "400",
"message": "Call failed!"
},
"body": {
"success": false,
"error_list": [
]
}
}
After every next system call fails, i am getting receipt_code, which i have to append to above json.
{
"header": {
"msgCode": "400",
"message": "Call failed!"
},
"body": {
"success": false,
"error_list": [
{
"errors": [
{
"message": "Invalid receipt code!"
}
],
"receipt_code": "A-11277809" //here is receipt_code
}
]
}
}
for all next calls if fail, then keep on appending this.
{
"header": {
"msgCode": "400",
"message": "Call failed!"
},
"body": {
"success": false,
"error_list": [
{
"errors": [
{
"message": "Invalid receipt code!"
}
],
"receipt_code": "11111"
},
{
"errors": [
{
"message": "Invalid receipt code!"
}
],
"receipt_code": "1222"
}
]
}
}
how can this be done by Groovy, any help
Here is my code
if(success!="true")
{
def receipt_code=receiptList[receiptFlag].receipt_code;
def error_list = []
def error ={
"errors": [
{
"message": "Invalid receipt code!"
}
],
"receipt_code": receipt_code //here is receipt_code
}
error_list.push(error)
error_list = JSON.stringify(error_list)
msg.put("error_list",error_list);
}
I am not able to add using above code
Using JsonSlurper
import groovy.json.*
String text = """
{
"header": {
"msgCode": "400",
"message": "Call failed!"
},
"body": {
"success": false,
"error_list": [
]
}
}
"""
def json = new JsonSlurper().parseText(text)
errors = [
['errors': [['message': 'hi']], 'code': 100],
['errors': [['message': 'hello']], 'code': 200]
]
for (err in errors)
json.body.error_list << err
println JsonOutput.toJson(json)
Output
{
"header": {
"msgCode": "400",
"message": "Call failed!"
},
"body": {
"success": false,
"error_list": [
{
"errors": [
{
"message": "hi"
}
],
"code": 100
},
{
"errors": [
{
"message": "hello"
}
],
"code": 200
}
]
}
}
Below is the JSON data retrieved successfully from the server in flutter application
{
"error": "false",
"notification": [
{
"rn": "1",
"id": "224",
"company_details": {
"code": "2",
}
},
{
"rn": "2",
"id": "219",
"company_details": {
"code": "3",
}
},
{
"rn": "3",
"id": "213",
"company_details": {
"code": "3",
}
},
{
"rn": "4",
"id": "209",
"company_details": {
"code": "4",
}
},
{
"rn": "5",
"id": "204",
"company_details": {
"code": "3",
}
},
{
"rn": "6",
"id": "199",
"company_details": {
"code": "3",
}
},
{
"rn": "7",
"id": "193",
"company_details": {
"code": "3",
}
}
],
}
The code used here is below
List notificationsList;
getnotifications(int page) async {
Map data = {
'user_id': “VICKY,
"page":page.toString()
};
var response = await http.post(companyorders, body: data);
if(response.statusCode == 200) {
jsonResponse = json.decode(response.body);
print('Response status: ${response.statusCode}');
print('Response body: ${response.body}');
String errorcheck = jsonResponse['error'];
companyDetail = NotificationModel.fromJson(json.decode(response.body));
companyDetail = NotificationModel.fromJson(json.decode(response.body));
print('names of companies');
print(companyDetail.content);
List list = jsonResponse['notification'];
notificationsList.add(list);
}
}
When I tried to add the list to the notificationsList I got the below error
Unhandled Exception: NoSuchMethodError: The method 'add' was called on
null. Receiver: null Tried calling: add(Instance(length:7) of
'_GrowableList')
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
I want to add the data retrieved to the notificationsList, how should I do that
You need to initialize notificationsList:
List notificationsList = [];
Also since list is an iterable therefore use addAll()
I've got the following JSON being sent to the server from the browser:
{
"title": "Testing again 2",
"abstract": "An example document",
"_href": "http://google.com",
"tags": [ "person" ],
"attributes": [ {
"id": 1,
"type": "TEXT",
"data": "test"
} ],
"sections": [ {
"id": 1,
"type": "LIST",
"data": [ {
"revision": 124,
"text": "test"
} ]
} ]
}
I need to make sure that the keys "_href", "id" and "revision" are not in the object anyplace at any level.
I found this but it doesn't quite work.
I searched npms.io and found has-any-deep which you can use after JSON.parse ing the JSON.
you need to parse json then check into the data
var str = '{
"title": "Testing again 2",
"abstract": "An example document",
"_href": "http://google.com",
"tags": [ "person" ],
"attributes": [ {
"id": 1,
"type": "TEXT",
"data": "test"
} ],
"sections": [ {
"id": 1,
"type": "LIST",
"data": [ {
"revision": 124,
"text": "test"
} ]
} ]
}';
var jsonObj = JSON.parse(str);
if ( typeof jsonObj._href == 'undefined') {
// check
}
A simple but not 100% foolproof solution would be to parse the JSON to string, and just search for your keys:
var a = JSON.stringify(JSONObject);
var occurs = false;
['"_href"', '"id"', '"version"'].forEach(function(string) {
if(a.indexOf(string) > -1) occurs = true;
});
The issue of course, is if there are values that match
'_href', 'id', 'version' in your JSON. But if you want to use native JS, I guess this is a good bet.
var a = {
"title": "Testing again 2",
"abstract": "An example document",
"tags": [ "person" ],
"attributes": [ {
"type": "TEXT",
"data": "test"
} ],
"sections": [ {
"type": "_href asdad",
"data": [ {
"text": "test"
} ]
} ]
},
b = {
"title": "Testing again 2",
"abstract": "An example document",
"_href": "http://google.com",
"tags": [ "person" ],
"attributes": [ {
"id": 1,
"type": "TEXT",
"data": "test"
} ],
"sections": [ {
"id": 1,
"type": "LIST",
"data": [ {
"revision": 124,
"text": "test"
} ]
} ]
},
aJson = JSON.stringify(a),
bJson = JSON.stringify(b);
var occursa = false, occursb = false;
['"_href"', '"id"', '"version"'].forEach(function(string) {
if(aJson.indexOf(string) > -1) { occursa = true};
});
['"_href"', '"id"', '"version"'].forEach(function(string) {
if(bJson.indexOf(string) > -1) { occursb = true};
});
console.log("a");
console.log(occursa);
console.log("b");
console.log(occursb);
You could use the optional second reviver parameter to JSON.parse for this:
function hasBadProp(json) {
let badProp = false;
JSON.parse(json, (k, v) => {
if ([_href", "id", "revision"].includes(k)) badProp = true;
return v;
});
return badProp;
}