How do I loop over Json data? - json

This is my json structure.
[
[
{
"nos": 0,
"name": "A S MUSIC AND DANCE A CULTURAL ORGANIZATION",
"unique_id": "AN/2020/0259067",
"reg_details": [
{
"registered_with": "Registrar of Societies"
},
{
"type_of_ngo": "Registered Societies (Non-Government)"
This is working fine.
String jsonString = await _loadANgoAsset();
final jsonResponse = json.decode(jsonString);
String name = jsonResponse[0][0]['name'];
debugPrint("Name of NGO is $name");
But when I want to loop throug a key of various entities of data using this code:
List<dynamic> allNamesOfNGO = jsonResponse[0][0]['name'];
allNamesOfNGO.forEach((allNamesOfNGO) {
(allNamesOfNGO as Map<String, dynamic>).forEach((key, value) {
print(key);
(value as Map<String, dynamic>).forEach((key2, value2) {
print(key2);
print(value2);
});
});
});
The following error occurs:
E/flutter ( 4683): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: type 'String' is not a subtype of type 'List<dynamic>'
Help please!

List<dynamic> allNamesOfNGO = jsonResponse[0][0]['name'];
This line tries to assign name of first ngo(String) to allNamesOfNGO(List), which results in the above error.
To overcome this error, replace the above code with this:
List<dynamic> allNamesOfNGO = jsonResponse[0];
allNamesOfNGO.forEach((allNamesOfNGO) {
(allNamesOfNGO as Map<String, dynamic>).forEach((key, value) {
print(key);
print(value);
if(key == "reg_details") {
value.forEach(regDetail) {
print(regDetail);
});
}
});
});
You don't need innermost forEach loop as you have already got the key, value pair before that loop. In the innermost forEach loop, you are trying to loop through individual key like nos, name and unique_is(which is either a string or an int) which isn't possible.
Value of reg_details is a list. So you can loop through it, but for that you have to check if key == "reg_details".

because you declare it as String and then loop it as dynamic .try
List<string>
instead of
List<dynamic>.

Related

Flutter: Unhandled Exception: type 'Null' is not a subtype of type 'String' when trying to run app

Trying to bulild app but it keeps crashing! When I click on the error it is leading me to two files video.dart and video_controller.dart.
It is pointing me on specific lines but when I click on them there is no specific error explanation of error I get. I tried to look for solution online but I can't understand what is this error telling me! If u know the solution please let me know!
ERROR:
/flutter ( 5006): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'Null' is not a subtype of type 'String'
E/flutter ( 5006): #0 Video.fromSnap
package:tiktok_project/models/video.dart:48
E/flutter ( 5006): #1 VideoController.onInit.<anonymous closure>
package:tiktok_project/controllers/video_controller.dart:19
video.dart :
import 'package:cloud_firestore/cloud_firestore.dart';
class Video {
String username;
String uid;
String id;
List likes;
int commentCount;
int shareCount;
String songName;
String caption;
String videoUrl;
String thumbnail;
String profilePhoto;
Video({
required this.username,
required this.uid,
required this.id,
required this.likes,
required this.commentCount,
required this.shareCount,
required this.songName,
required this.caption,
required this.videoUrl,
required this.profilePhoto,
required this.thumbnail,
});
Map<String, dynamic> toJson() => {
"username": username,
"uid": uid,
"profilePhoto": profilePhoto,
"id": id,
"likes": likes,
"commentCount": commentCount,
"shareCount": shareCount,
"songName": songName,
"caption": caption,
"videoUrl": videoUrl,
"thumbnail": thumbnail,
};
static Video fromSnap(DocumentSnapshot snap) {
var snapshot = snap.data() as Map<String, dynamic>;
return Video(
username: snapshot['username'],
uid: snapshot['uid'],
id: snapshot['id'],
likes: snapshot['likes'],
commentCount: snapshot['commentCount'],
shareCount: snapshot['shareCount'],
songName: snapshot['songName'],
caption: snapshot['caption'],
videoUrl: snapshot['videoUrl'],
profilePhoto: snapshot['profilePhoto'],
thumbnail: snapshot['thumbnail'],
);
}
}
video_controller.dart:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:get/get.dart';
import 'package:tiktok_project/const.dart';
import 'package:tiktok_project/models/video.dart';
class VideoController extends GetxController {
final Rx<List<Video>> _videoList = Rx<List<Video>>([]);
List<Video> get videoList => _videoList.value;
#override
void onInit() {
super.onInit();
_videoList.bindStream(
firestore.collection('videos').snapshots().map((QuerySnapshot query) {
List<Video> retVal = [];
for (var element in query.docs) {
retVal.add(
Video.fromSnap(element),
);
}
return retVal;
}));
}
likeVideo(String id) async {
DocumentSnapshot doc = await firestore.collection('videos').doc(id).get();
var uid = authController.user.uid;
if ((doc.data() as dynamic)['likes'].contains(uid)) {
await firestore.collection('videos').doc(id).update({
'likes': FieldValue.arrayRemove([uid])
});
} else {}
await firestore.collection('videos').doc(id).update({
'likes': FieldValue.arrayUnion([uid])
});
}
}
That's a null safety error.
You need to do something like this
username: snapshot['username'] ?? '',
For each element that is String, or use the type "String?" with the interrogation point telling the compiler that this field may be null
Apparently I can't reproduce the error since I don't have access to your firestore documents, but I am pretty certain that the problem occurs in
...
for (var element in query.docs) {
retVal.add(
Video.fromSnap(element),
);
}
...
where you attempt to translate element JSON into a Video. In fromSnap, before returning, try printing out snapshot. You should see that it is missing one or more attributes (which is why it was complaining about having a Null when it should be a String), or have some incorrect attributes.

jsondata error '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Iterable<dynamic>'

How can I get information from this code Jason I don't know what the problem is?
I tried to get the total at the end of Jason's code and the information inside the data, but it shows me this error.
the error
GetLogsData error is: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Iterable<dynamic>'
here is the jonData
i wanna get data and total from logs object
{
"logs": {
"data": [
{
"description": "Failed Login Attempt",
"created_at": "2022-07-21T13:58:49.000000Z"
}
],
"total": 21
},
"totalLogs": 21
}
here is the code:
in here getting the logs
Future GetLogsData() async {
try {
var response = await CallApi().getData('logs');
jsonResponse = json.decode(response.body);
List<_LogsList> Logs_List = [];
for (var index in jsonResponse) {
_LogsList logsList = _LogsList(
data: index['data'] ?? '',
total: index['total'] ?? '',
);
Logs_List.add(logsList);
}
return Logs_List;
}catch (e) {
print('GetLogsData error is: $e');
return[];
}
}
this is storeing list
class _LogsList {
final dynamic total;
final List<Map<String, dynamic>> data;
_LogsList( {this.total, this.data, });
}
I think your json has extra coma in it. It should have to look like this.
{
"logs": {
"data": [
{
"description": "Failed Login Attempt",
"created_at": "2022-07-21T13:58:49.000000Z"
}
],
"total": 21
},
"totalLogs": 21
}
In my opinion, you should first create a Log class with ` factory method, this way you'll be able to easily generate a list of logs. Follow these steps,
Step 1 : Create a Log class
class Log {
final String description, createdAt;
const Log({
required this.description,
required this.createdAt,
});
factory Log.fromData(Map<String, dynamic> data) {
return Log(
description: data['description'],
createdAt: data['created_at'],
);
}
}
Step 2 : Decode the response and convert it to a list of logs
final data = json.decode(response.body);
final List<Log> logs = data['logs']['data']
.map<Log>((logData) => Log.fromData(logData))
.toList();
After this, based on your code, you can choose to create an extra LogList class or can directly extract total number of logs, but the base should be this, Good luck!

Flutter converting Nested Object from Json returns null

I have a Nested Object like this just a bit bigger:
"name": "String",
"exercise": [
{
"index": 1,
}
],
"pause": [
{"index":2},
]
I convert the exercise and pause to a Json String and save them in a column in SQFLite.
The problem
When I read the Data everything works fine including the List (not nested) but both list's of nested Object are empty when I read a value of the nested object it gives an error.
item.exercise[0].index.toString()
Valid Value range is empty: 0
When I read only item.exercise.toString() it returns []. Without != null ? [...] : List<Exercise>() it also throws an error
Data I get from my Database (shortened)
List of:
[{name: number 1, id: 56, exercise: [{"index":1,"weightGoal":[15,16,17]}, {"index":3,"weightGoal":[15,16,17]}], pause: [{"index":2}]},{"index":4}]}]
What I do with it
Here I try to go through the list and convert it into a List of PlanModel:
List<PlanModel> list =
res.isNotEmpty ? res.map((c) => PlanModel.fromJson(c)).toList() : [];
return list;
Full model
PlanModel planModelFromJson(String str) => PlanModel.fromJson(json.decode(str));
String planModelToJson(PlanModel data) => json.encode(data.toJson());
class PlanModel {
PlanModel({
this.name,
this.id,
this.workoutDays,
this.pastId,
this.timesDone,
this.exercise,
this.pause,
});
String name;
int id;
List<String> workoutDays;
int pastId;
int timesDone;
List<Exercise> exercise;
List<Pause> pause;
factory PlanModel.fromJson(Map<String, dynamic> json) => PlanModel(
name: json["name"],
id: json["id"],
workoutDays: List<String>.from(jsonDecode(json["workoutDays"])),
pastId: json["pastId"],
timesDone: json["timesDone"],
exercise: json["Exercise"] != null ? new List<Exercise>.from(json["Exercise"].map((x) => Exercise.fromJson(x))): List<Exercise>(),
pause: json["Pause"] != null ? new List<Pause>.from(json["Pause"].map((x) => Pause.fromJson(x))): List<Pause>(),
);
Map<String, dynamic> toJson() => {
"name": name,
"id": id,
"workoutDays": List<dynamic>.from(workoutDays.map((x) => x)),
"pastId": pastId,
"timesDone": timesDone,
"Exercise": List<dynamic>.from(exercise.map((x) => x.toJson())),
"Pause": List<dynamic>.from(pause.map((x) => x.toJson())),
};
}
class Exercise {
Exercise({
this.index,
this.name,
this.goal,
this.repGoal,
this.weightGoal,
this.timeGoal,
this.setGoal,
});
int index;
String name;
int goal;
int repGoal;
List<int> weightGoal;
int timeGoal;
List<String> setGoal;
Exercise.fromJson(dynamic json) {
// anything that is wrapped around with this [] in json is converted as list
// anything that is wrapped around with this {} is map
index = json["index"];
name = json["name"];
goal = json["goal"];
repGoal = json["repGoal"];
weightGoal = json["weightGoal"] != null ? json["weightGoal"].cast<int>() : [];
timeGoal = json["timeGoal"];
setGoal = json["setGoal"] != null ? json["setGoal"].cast<String>() : [];
}
Map<String, dynamic> toJson() => {
"index": index,
"name": name,
"goal": goal,
"repGoal": repGoal,
"weightGoal": List<dynamic>.from(weightGoal.map((x) => x)),
"timeGoal": timeGoal,
"setGoal": List<dynamic>.from(setGoal.map((x) => x)),
};
}
class Pause {
Pause({
this.index,
this.timeInMilSec,
});
int index;
int timeInMilSec;
factory Pause.fromJson(Map<String, dynamic> json) => Pause(
index: json["index"],
timeInMilSec: json["timeInMilSec"],
);
Map<String, dynamic> toJson() => {
"index": index,
"timeInMilSec": timeInMilSec,
};
}
Read this first.
You need to tweek this code a little to work for you but the idea is that;
also read comment in the code.
if json string comes with [] those around, json.decode will decode it as List<Map>.
if it comes with {} this json.decode will decode it as Map.
note: be careful while using generics on json.decode I reccommend not to.
data inside the jsonString does not really corresponds with the values inside the fromJson function. json string which you have provided was not really good. so I think you will understand how to manipulate it for your needs.
also main constructor Exercise you can use for initial data.
import 'dart:convert';
class Exercise{
Exercise({this.index,
this.name,
this.repGoal,
this.weightGoal,
this.setGoal});
String index;
String name;
String repGoal;
String weightGoal;
String setGoal;
Exercise.fromJson(dynamic json) :
// anything that is wrapped around with this [] in json is converted as list
// anything that is wrapped around with this {} is map
index = json["exercise"][0]["index"].toString(),
name = json["name"].toString(),
repGoal = json["repGoal"].toString(),
weightGoal = json["weightGoal"].toString(),
setGoal = json["setGoal"].toString();
}
void main(){
String jsonString = '{name: number 1, id: 56, exercise: [{"index":1,"weightGoal":[15,16,17], pause: [{"index":2}]}';
Map json = json.decode(jsonString);
Exercise.fromJson(json);
}
I found it out :)
I have restructured my fromJson to this, especially the jsonDecode was important, because json["exercise "] was only a String.
PlanModel.fromJson(dynamic json) {
name = json["name"];
if (json["exercise"] != null) {
exercise = [];
jsonDecode(json["exercise"]).forEach((v) {
exercise.add(Exercise.fromJson(v));
});
}}
now I can access it with
PlanModel item = snapshot.data[index];
item.exercise[0].timeGoal.toString()

type 'int' is not a subtype of type 'double' -- Dart/Flutter Error

So I have an API set up that returns the following output on a specific endpoint when called:
{
"total_user_currency": 0.1652169792,
"total_sats": 2184,
"total_btc": 0.00002184,
"outputArray": [
{
"txid": "642fd534cb3a670a31f4d59e70452b133b0b461d871db44fcc91d32bb6b6f0cc",
"vout": 2,
"status": {
"confirmed": true,
"block_height": 625673,
"block_hash": "0000000000000000000310649c075b9e2fed9b10df2b9f0831efc4291abcb7fb",
"block_time": 1586732907
},
"value": 546
},
]
}
And I'm using the following dart class to decode that JSON into an Object that I can interact with:
class UtxoData {
final dynamic totalUserCurrency;
final int satoshiBalance;
final dynamic bitcoinBalance;
List<UtxoObject> unspentOutputArray;
UtxoData({this.totalUserCurrency, this.satoshiBalance, this.bitcoinBalance, this.unspentOutputArray});
factory UtxoData.fromJson(Map<String, dynamic> json) {
var outputList = json['outputArray'] as List;
List<UtxoObject> utxoList = outputList.map((output) => UtxoObject.fromJson(output)).toList();
return UtxoData(
totalUserCurrency: json['total_user_currency'],
satoshiBalance: json['total_sats'],
bitcoinBalance: json['total_btc'],
unspentOutputArray: utxoList
);
}
}
class UtxoObject {
final String txid;
final int vout;
final Status status;
final int value;
UtxoObject({this.txid, this.vout, this.status, this.value});
factory UtxoObject.fromJson(Map<String, dynamic> json) {
return UtxoObject(
txid: json['txid'],
vout: json['vout'],
status: Status.fromJson(json['status']),
value: json['value']
);
}
}
class Status {
final bool confirmed;
final String blockHash;
final int blockHeight;
final int blockTime;
Status({this.confirmed, this.blockHash, this.blockHeight, this.blockTime});
factory Status.fromJson(Map<String, dynamic> json) {
return Status(
confirmed: json['confirmed'],
blockHash: json['block_hash'],
blockHeight: json['block_height'],
blockTime: json['block_time']
);
}
}
Here is the function that actually calls the API in the code:
Future<UtxoData> fetchUtxoData() async {
final requestBody = {
"currency": "USD",
"receivingAddresses": ["bc1q5jf6r77vhdd4t54xmzgls823g80pz9d9k73d2r"],
"internalAndChangeAddressArray": ["bc1q5jf6r77vhdd4t54xmzgls823g80pz9d9k73d2r"]
};
final response = await http.post('https://thisisanexmapleapiurl.com', body: jsonEncode(requestBody), headers: {'Content-Type': 'application/json'} );
if (response.statusCode == 200 || response.statusCode == 201) {
notifyListeners();
print(response.body);
return UtxoData.fromJson(json.decode(response.body));
} else {
throw Exception('Something happened: ' + response.statusCode.toString() + response.body );
}
}
However, when I do run the function, I get the following error in my editor:
Exception has occurred.
_TypeError (type 'int' is not a subtype of type 'double')
I get it on the return UtxoData statement inside the factory method for the UtxoData class as shown below:
return UtxoData(
totalUserCurrency: json['total_user_currency'],
satoshiBalance: json['total_sats'], <<<<============= The exception pops up right there for some reason
bitcoinBalance: json['total_btc'],
unspentOutputArray: utxoList
);
This is strange because I know that the API is returning an int there. totalUserCurrency and bitcoinBalance have to be dynamic because they can either be 0 (an int) or an arbitrary number like 12942.3232 (a double).
Why do I get this error and how can I correct this? Much appreciated
I'd a similar problem where the amount I was getting from an API veried between 0 and few thousands including decimals. I tried the following :
this.balanceAmount = double.parse(json['total_balance']??'0.0'.toString());
This didn't work with my dataset. So, I enhanced it to the following which worked in all the cases for my dataset. You might need slight enhacement(s).
double parseAmount(dynamic dAmount){
double returnAmount = 0.00;
String strAmount;
try {
if (dAmount == null || dAmount == 0) return 0.0;
strAmount = dAmount.toString();
if (strAmount.contains('.')) {
returnAmount = double.parse(strAmount);
} // Didn't need else since the input was either 0, an integer or a double
} catch (e) {
return 0.000;
}
return returnAmount;
}
If you are parsing data, and you are unsure if it will be an Int or a double there are multiple solutions.
If you need an Int use parsedData.truncate() this works for both Int and double and it resolves into an Int by discarding decimals. Similarly you could also use cail() or floor() if you want the decimals to have some effect in the outcome.
So, in your case, you would only need to do like this:
satoshiBalance: json['total_sats'].truncate(),
I hope this helps!

Kafka Streams API GroupBy behaviour

I am new in kafka streams and I am trying to aggregate some streaming data into a KTable using groupBy function. The problem is the following:
The produced message is a json msg with the following format:
{ "current_ts": "2019-12-24 13:16:40.316952",
"primary_keys": ["ID"],
"before": null,
"tokens": {"txid":"3.17.2493",
"csn":"64913009"},
"op_type":"I",
"after": { "CODE":"AAAA41",
"STATUS":"COMPLETED",
"ID":24},
"op_ts":"2019-12-24 13:16:40.316941",
"table":"S_ORDER"}
I want to isolate the json field "after" and then create a KTable with "key" = "ID" and value the whole json "after".
Firstly, I created a KStream to isolate the "after" json, and it works fine.
KStream code block: (Don't pay attention to the if statement because "before" and "after" have the same format.)
KStream<String, String> s_order_list = s_order
.mapValues(value -> {
String time;
JSONObject json = new JSONObject(value);
if (json.getString("op_type").equals("I")) {
time = "after";
}else {
time = "before";
}
JSONObject json2 = new JSONObject(json.getJSONObject(time).toString());
return json2.toString();
});
The output, as expected, is the following:
...
null {"CODE":"AAAA48","STATUS":"SUBMITTED","ID":6}
null {"CODE":"AAAA16","STATUS":"COMPLETED","ID":1}
null {"CODE":"AAAA3","STATUS":"SUBMITTED","ID":25}
null {"CODE":"AAAA29","STATUS":"SUBMITTED","ID":23}
...
Afterwards, I implement a KTable to groupBy the "ID" of the json.
KTable code block:
KTable<String, String> s_table = s_order_list
.groupBy((key, value) -> {
JSONObject json = new JSONObject(value);
return json.getString("ID");
});
And there is an error that I want to create KTable<String, String> but I am creating GroupedStream<Object,String>.
Required type: KTable<String,String>
Provided:KGroupedStream<Object,String>
no instance(s) of type variable(s) KR exist so that KGroupedStream<KR, String> conforms to KTable<String, String>
In conclusion, the question is what exactly are KGroupedStreams and how to implement a KTable properly ?
After groupBy processor, you can use a stateful processor, like aggregate or reduce (that processors returns KTable). You can do something like this:
KGroupedStream<String, String> s_table = s_order_list
.groupBy((key, value) ->
new JSONObject(value).getString("ID"),
Grouped.with(
Serdes.String(),
Serdes.String())
);
KTable<String, StringAggregate> aggregateStrings = s_table.aggregate(
(StringAggregate::new),
(key, value, aggregate) -> aggregate.addElement(value));
StringAggregate looks like:
public class StringAggregate {
private List<String> elements = new ArrayList<>();
public StringAggregate addElement(String element){
elements.add(element);
return this;
}
//other methods
}