Accessing a nested list of objects in dart - list

I have a list of Care requirements name care requirements list which consist of requirement_id, requirement_name and care_levels_list which is inside the care requirements list.The care requirements list is retrieved through an API response and is in the format
[CareRequirement(1, Requirement 1, [{care_level_id: 1, care_level_name: no-help, price: 2000.00}, {care_level_id: 2, care_level_name: supervise, price: 1000.00}, {care_level_id: 3, care_level_name: assist, price: 1000.00}]), CareRequirement(2, Requirement 2, [{care_level_id: 2, care_level_name: supervise, price: 3000.00}]),
how can I access the price of the care level id 1 of requirement 1?
CareRquirement model
class CareRequirement extends Equatable {
int id = 0;
String name = '';
List careLevelsList = [];
CareRequirement(
{required this.id, required this.name, required this.careLevelsList});
#override
List<Object?> get props => [id, name, careLevelsList];
#override
CareRequirement.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
careLevelsList = json['care_levels'];
}
Map toJson() {
Map jsonData = {
"id": id,
"name": name,
"care_levels": careLevelsList,
};
return jsonData;
}
static pure() {
return CareRequirement(
id: 0,
name: '',
careLevelsList: [],
);
}
}

Related

Fetch user details from another model

I have a model(Poll) which contains another model(User) with user details.
I want to get the Username of who posted a poll
but the below is error occurred
I/flutter (21892): type 'int' is not a subtype of type 'String'
this is my model class(flutter)
import 'dart:convert';
class Poll {
Poll({
required this.id,
required this.choices,
required this.question,
required this.pubDate,
required this.createdBy,
});
late final int id;
late final List<Choices> choices;
late final String question;
late final String pubDate;
late final User createdBy;
Poll.fromJson(Map<String, dynamic> json) {
id = json['id'];
choices =
List.from(json['choices']).map((e) => Choices.fromJson(e)).toList();
question = json['question'];
pubDate = json['pub_date'];
createdBy = User.fromJson(jsonDecode(json['created_by']));
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['id'] = id;
_data['choices'] = choices.map((e) => e.toJson()).toList();
_data['question'] = question;
_data['pub_date'] = pubDate;
_data['created_by'] = createdBy.toJson();
return _data;
}
}
class Choices {
Choices({
required this.id,
required this.choiceText,
required this.poll,
});
late final int id;
late final String choiceText;
late final int poll;
Choices.fromJson(Map<String, dynamic> json) {
id = json['id'];
choiceText = json['choice_text'];
poll = json['poll'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['id'] = id;
_data['choice_text'] = choiceText;
_data['poll'] = poll;
return _data;
}
}
class User {
User({
required this.id,
required this.password,
required this.lastLogin,
required this.isSuperuser,
required this.username,
required this.firstName,
required this.lastName,
required this.email,
required this.isStaff,
required this.isActive,
required this.dateJoined,
required this.groups,
required this.userPermissions,
});
late final int id;
late final String password;
late final String lastLogin;
late final bool isSuperuser;
late final String username;
late final String firstName;
late final String lastName;
late final String email;
late final bool isStaff;
late final bool isActive;
late final String dateJoined;
late final List<dynamic> groups;
late final List<dynamic> userPermissions;
User.fromJson(Map<String, dynamic> json) {
id = json['id'];
password = json['password'];
lastLogin = json['last_login'];
isSuperuser = json['is_superuser'];
username = json['username'];
firstName = json['first_name'];
lastName = json['last_name'];
email = json['email'];
isStaff = json['is_staff'];
isActive = json['is_active'];
dateJoined = json['date_joined'];
groups = List.castFrom<dynamic, dynamic>(json['groups']);
userPermissions = List.castFrom<dynamic, dynamic>(json['user_permissions']);
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['id'] = id;
_data['password'] = password;
_data['last_login'] = lastLogin;
_data['is_superuser'] = isSuperuser;
_data['username'] = username;
_data['first_name'] = firstName;
_data['last_name'] = lastName;
_data['email'] = email;
_data['is_staff'] = isStaff;
_data['is_active'] = isActive;
_data['date_joined'] = dateJoined;
_data['groups'] = groups;
_data['user_permissions'] = userPermissions;
return _data;
}
}
here is how I am parsing the json
List<Poll> _polls = [];
Future<bool> getOffers() async {
var url = Uri.parse(polls_uri);
try {
http.Response response = await http.get(url);
var data = json.decode(response.body);
List<Poll> temp = [];
for (var element in data) {
Poll poll = Poll.fromJson(element);
temp.add(poll);
}
_polls = temp;
return true;
} catch (e) {
print(e);
return false;
}
}
List<Poll> get polls {
return [..._polls];
}
this is where i want to display I want to display the details
ListView.builder(
itemCount: polls.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(polls[index].question),
Text(polls[index].createdBy.username),
]),
),
);
},
),
my model class(django)
class Poll(models.Model):
question = models.CharField(max_length=100)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
pub_date = models.DateTimeField(auto_now=True)
def __str__(self):
return self.question
serializer
class PollSerializer(serializers.ModelSerializer):
choices = ChoiceSerializer(many=True, read_only=True, required = False)
class Meta:
model = Poll
fields = '__all__'
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
views
class PollList(generics.ListCreateAPIView):
queryset = Poll.objects.all() [:20]
serializer_class = PollSerializer
Poll Json data: the key "created_by" is a model of class user... It is from the class I want to get the username
{
"id": 3,
"choices": [
{
"id": 9,
"choice_text": "Day",
"poll": 3
},
{
"id": 10,
"choice_text": "Boarding",
"poll": 3
},
{
"id": 11,
"choice_text": "Mixed",
"poll": 3
}
],
"created_by": 1,
"question": "Type of School: Day or Boarding",
"pub_date": "2022-07-21T13:29:23.445097Z"
},

Flutter - Fill future list from json

I want to fill a list from json.
Future<List<Titles>> fetchTitle() async {
String url = "https://jsonplaceholder.typicode.com/posts";
final response = await http.get(url,headers: {'Content-Type': 'application/json'});
return titlesFromJson(utf8.decode(response.bodyBytes));
How to fill below list using fetchTitle method. I want to add "title" item from json.
final List myLists = [];
Expanded(
child: GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 1,
padding: EdgeInsets.only(left: 20, top: 20, right: 20),
children:List.generate(myLists.length, (index) {
return InkWell(
From the official documentation this is the way on how to fetch data from json and convert the response to list of model:
1- create a model for the post
class Post {
int userId;
int id;
String title;
String body;
Post({this.userId, this.id, this.title, this.body});
Post.fromJson(Map<String, dynamic> json) {
userId = json['userId'];
id = json['id'];
title = json['title'];
body = json['body'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['userId'] = this.userId;
data['id'] = this.id;
data['title'] = this.title;
data['body'] = this.body;
return data;
}
}
2 - import http package and fetch post from the link https://jsonplaceholder.typicode.com/posts
import 'package:http/http.dart' as http;
Future<List<Post>> fetchPosts(http.Client client) async {
final response = await client
.get('https://jsonplaceholder.typicode.com/posts');
return parsePosts(response.body);
}
3 - Use the method that you define on your model to create a list that contain posts
import 'dart:convert';
List<Post> parsePosts(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<Post>((json) => Post.fromJson(json)).toList();
}
4 - to make a test that your code work, create a simple async main method that call fetchPosts with the await prefix because fetchPosts return a Future so if you don't use await you will get a future and not the List
void main() async {
List posts = await fetchPosts(http.Client());
// this will print the id and the title of posts
posts.forEach((post) => print('Post id: ${post.id} | Post title: ${post.title}'));
}
I hope this help!
To add the JSON result to a list, you may need to wait for the response and add it to the List. Since fetchTitle() method returns Future<List<Titles>>, when you await for it, you will get a List<Titles> which can be assigned to your myList.
myList = await fetchTitle();
Since we are using await, we may need to mark the method using async keyword.
void main() async {
List myList = [];
myList = await fetchTitle();
print(myList);
}

How to delete duplicates of a List<MyDataModel> (Dart/Flutter)

I have a futurebuilder that builds the UI based on a List, it does the job, however I get duplicates due to the UI being built again and again whenever I navigate. My question is, is there a innate method in Dart that can remove duplicates from a list? I've tried this StackOverflow question however it doesn't work.
Here is my custom model:
class HomeList {
Widget navigateScreen;
String imagePath;
PatientInfo patientInfo;
HomeList({
this.navigateScreen,
this.imagePath = '',
this.patientInfo,
});
static List<HomeList> homeList = [];
}
Here is my function for the futureBuilder i'm getting the data from my cloud_firestore:
_getPatients() async {
if (didLoadpatients == 0) {
print('this is didloadpatients at start of func $didLoadpatients');
var document = await db
.collection('users')
.document(mUser.uid)
.collection('patients');
document.getDocuments().then((QuerySnapshot query) async {
query.documents.forEach((f) {
uids.add(f.data['uID']);
});
didLoadpatients++;
print('this is didloadpatients at end of func $didLoadpatients');
for (var i = 0; i < uids.length; i++) {
var userDocuments = await db.collection('users').document(uids[i]);
userDocuments.get().then((DocumentSnapshot doc) {
print(doc.data);
homeList.add(HomeList(
imagePath: 'assets/fitness_app/fitness_app.png',
patientInfo: new PatientInfo.fromFbase(doc.data)));
});
print(homeList);
}
});
} else
print('I am leaving the get patient function');
}
Future<bool> getData() async {
_getCurrentUser();
await Future.delayed(const Duration(milliseconds: 1500), () async {
_getPatients();
});
return true;
}
Any help would be appreciated thank you!
To remove duplicates you can use Set Data Structure instead of List.
Just use Set instead of List to get unique values only.
Before Adding you can Remove Element from model this will Work
dummymodel.removeWhere((m) => m.id == id);
dummymodel.add(dummymodel.fromJson(data));
To Remove Duplicates from Data Model simply use Set (Data structure),
Original List with Duplicate Entries:
List<MyDataModel> mList = [MyDataModel(1), MyDataModel(2), MyDataModel(1), MyDataModel(3)];
New List that removes duplicate Entries from your List<MyDataModel>:
List<MyDataModel> mNewList = list.toSet().toList();
Output:
The result will be like
MyDataModel(1), MyDataModel(2), MyDataModel(3)
To remove the duplicate elements from custom object list, you need to override == and hashcode methods in your POJO class and then add the items in Set and again convert set to list to remove duplicate objects. Below is the working code:-
class TrackPointList {
double latitude;
double longitude;
String eventName;
Time timeZone;
TrackPointList({
this.latitude,
this.longitude,
this.eventName,
this.timeZone,
});
#override
bool operator==(other) {
// Dart ensures that operator== isn't called with null
// if(other == null) {
// return false;
// }
if(other is! TrackPointList) {
return false;
}
// ignore: test_types_in_equals
return eventName == (other as TrackPointList).eventName;
}
int _hashCode;
#override
int get hashCode {
if(_hashCode == null) {
_hashCode = eventName.hashCode;
}
return _hashCode;
}
factory TrackPointList.fromJson(Map<String, dynamic> json) => TrackPointList(
latitude: json["latitude"].toDouble(),
longitude: json["longitude"].toDouble(),
eventName: json["eventName"],
timeZone: timeValues.map[json["timeZone"]],
);
Map<String, dynamic> toJson() => {
"latitude": latitude,
"longitude": longitude,
"eventName": eventName,
"timeZone": timeValues.reverse[timeZone],
};
}
Above is the POJO class. Now below is the method which helps you to filter the objects according to the eventName data member.
List<TrackPointList> getFilteredList(List<TrackPointList> list){
final existing = Set<TrackPointList>();
final unique = list
.where((trackingPoint) => existing.add(trackingPoint))
.toList();
return unique;
}
This will work definitely.
Please +1 if it helps you.
I've come up with quite a brute force solution. Instead of
_getPatients() async {
if (didLoadpatients == 0) {
print('this is didloadpatients at start of func $didLoadpatients');
var document = await db
.collection('users')
.document(mUser.uid)
.collection('patients');
document.getDocuments().then((QuerySnapshot query) async {
query.documents.forEach((f) {
uids.add(f.data['uID']);
});
didLoadpatients++;
print('this is didloadpatients at end of func $didLoadpatients');
for (var i = 0; i < uids.length; i++) {
var userDocuments = await db.collection('users').document(uids[i]);
userDocuments.get().then((DocumentSnapshot doc) {
print(doc.data);
homeList.add(HomeList(
imagePath: 'assets/fitness_app/fitness_app.png',
patientInfo: new PatientInfo.fromFbase(doc.data)));
});
print(homeList);
}
});
} else
print('I am leaving the get patient function');
}
I've done what #Jay Mungara says and clear my Set everytime my UI rebuilds:
_getPatients() async {
homeList.clear();
if (didLoadpatients == 0) {
print('this is didloadpatients at start of func $didLoadpatients');
var document = await db
.collection('users')
.document(mUser.uid)
.collection('patients');
document.getDocuments().then((QuerySnapshot query) async {
query.documents.forEach((f) {
uids.add(f.data['uID']);
});
didLoadpatients++;
print('this is didloadpatients at end of func $didLoadpatients');
for (var i = 0; i < uids.length; i++) {
var userDocuments = await db.collection('users').document(uids[i]);
userDocuments.get().then((DocumentSnapshot doc) {
print(doc.data);
homeList.add(HomeList(
imagePath: 'assets/fitness_app/fitness_app.png',
patientInfo: new PatientInfo.fromFbase(doc.data)));
});
print(homeList);
}
});
} else
print('I am leaving the get patient function');
}
Thank you for all your answers!
this is a small examples to remove duplicate element
removeDuplicate() {
List<dynamic> demoList = [
{"userId": 1, "id": 1, "name": "thappu1"},
{"userId": 2, "id": 2, "name": "appu"},
{"userId": 1, "id": 1, "name": "thappu1"},
{"userId": 2, "id": 2, "name": "appu"},
{"userId": 2, "id": 2, "name": "appu"},
{"userId": 2, "id": 2, "name": "appu"},
{"userId": 2, "id": 2, "name": "appu"},
];
var toRemove = {};
demoList.forEach((e) {
toRemove.putIfAbsent("$e", () => e);
});
print(toRemove.keys.toList());
}
output is
[{userId: 1, id: 1, name: thappu1}, {userId: 2, id: 2, name: appu}]

How can I define new generic list of objects in Swift?

I can easy define new collection with some object type in C#, using the next code:
class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
// in some other method
var listPesrons = new List<Person>
{
new Person { Id = 0, Name = "Oleg" },
new Person { Id = 1, Name = "Lena" }
};
What is the analog for Swift programming language for the code list above?
The close equivalent would be:
public class Person {
public var id: Int
public var name: String
public init(id: Int, name: String) {
self.id = id
self.name = name
}
}
var listPersons = [
Person(id: 0, name: "Oleg"),
Person(id: 1, name: "Lena")
]
If using a struct, the code is very similar:
public struct Person {
public var id: Int
public var name: String
}
// persons will be an Swift Array
let persons = [
Person(id: 0, name: "Oleg"),
Person(id: 1, name: "Lena"),
]
If you wanted a class instead of a struct (and generally, you might want to think about a struct first, and a class only if you really need the features classes bring) then you'll also need an initializer:
public class Person {
public var id: Int
public var name: String
public init(id: Int, name: String) {
self.id = id
self.name = name
}
}

RavenDB Map/Reduce/Transform on nested, variable-length arrays

I'm new to RavenDB, and am loving it so far. I have one remaining index to create for my project.
The Problem
I have thousands of responses to surveys (i.e. "Submissions"), and each submission has an array of answers to specific questions (i.e. "Answers"), and each answer has an array of options that were selected (i.e. "Values").
Here is what a single Submission basically looks like:
{
"SurveyId": 1,
"LocationId": 1,
"Answers": [
{
"QuestionId": 1,
"Values": [2,8,32],
"Comment": null
},
{
"QuestionId": 2,
"Values": [4],
"Comment": "Lorem ipsum"
},
...more answers...
]
}
More Problem: I have to able to filter by SurveyId, LocationId, QuestionId, Creation Date. As I understand it, that's done at query time... I just need to make sure that these properties are present in the transformation result (or is it the reduce result? or both?). If I'm right, then this is less of an issue.
The Required Result
We need one object per question per survey that gives the sum of each option. Hopefully it's self explanatory:
[
{
SurveyId: 1,
QuestionId: 1,
NumResponses: 976,
NumComments: 273,
Values: {
"1": 452, // option 1 selected 452 times
"2": 392, // option 2 selected 392 times
"4": 785 // option 4 selected 785 times
}
},
{
SurveyId: 1,
QuestionId: 2,
NumResponses: 921,
NumComments: 46,
Values: {
"1": 325,
"2": 843,
"4": 119,
"8": 346,
"32": 524
}
},
...
]
My Attempt
I didn't get very far, and I think this post is heading me down the right path, but it doesn't help me with the list of Values. I've searched and searched but can't find any direction for what do with a nested array like that. Here's that I have so far:
MAP:
from submission in docs.Submissions
from answer in submission.Answers
where answer.WasSkipped != true && answer.Value != null
select new {
SubmissionDate = submission["#metadata"]["Last-Modified"],
SurveyId = submission.SurveyId,
LocationId = submission.LocationId,
QuestionId = answer.QuestionId,
Value = answer.Value
}
REDUCE:
??
TRANSFORM:
from result in results
from answer in result.Answers
where answer.WasSkipped != true && answer.Value != null
select new {
SubmissionDate = result["#metadata"]["Last-Modified"],
SurveyId = result.SurveyId,
LocationId = result.LocationId,
QuestionId = answer.QuestionId,
Value = answer.Value
}
For what it's worth, this is hosted on RavenHQ.
It's been so long that I've been working on this and can't get it right. Any help in getting me to the required result is very appreciated!
Assuming your C# classes look like this:
public class Submission
{
public int SurveyId { get; set; }
public int LocationId { get; set; }
public IList<Answer> Answers { get; set; }
}
public class Answer
{
public int QuestionId { get; set; }
public int[] Values { get; set; }
public string Comment { get; set; }
}
If you are running RavenDB 2.5.2637 or higher, you can now use a dictionary result type:
public class Result
{
public int SurveyId { get; set; }
public int QuestionId { get; set; }
public int NumResponses { get; set; }
public int NumComments { get; set; }
public Dictionary<int, int> Values { get; set; }
}
If you are running anything earlier (including 2.0 releases), then you won't be able to use a dictionary, but you can use an IList<KeyValuePair<int,int>> instead.
Here is the index:
public class TestIndex : AbstractIndexCreationTask<Submission, Result>
{
public TestIndex()
{
Map = submissions =>
from submission in submissions
from answer in submission.Answers
select new
{
submission.SurveyId,
answer.QuestionId,
NumResponses = 1,
NumComments = answer.Comment == null ? 0 : 1,
Values = answer.Values.ToDictionary(x => x, x => 1)
//Values = answer.Values.Select(x => new KeyValuePair<int, int>(x, 1))
};
Reduce = results =>
from result in results
group result by new { result.SurveyId, result.QuestionId }
into g
select new
{
g.Key.SurveyId,
g.Key.QuestionId,
NumResponses = g.Sum(x => x.NumResponses),
NumComments = g.Sum(x => x.NumComments),
Values = g.SelectMany(x => x.Values)
.GroupBy(x => x.Key)
.ToDictionary(x => x.Key, x => x.Sum(y => y.Value))
//.Select(x => new KeyValuePair<int, int>(x.Key, x.Sum(y => y.Value)))
};
}
}
(No transform step is needed.)
If you can't use 2.5.2637 or higher, then replace the .ToDictionary lines with the commented lines just below them, and use an IList<KeyValuePair<int,int>> in the result class.
The fix to allow dictionaries in the map/reduce was based on this issue which your post helped to identify. Thank you!