Adding firestore subcollection fields into List - flutter

i am trying to add the fields of a subcollection into reviewsList. May i know how should I do that in the //To add to List// part?
The 'Reviews' collection contains 2 subcollections namely '1' and '2'. Both '1' and '2' each contain a map of 4 fields.
Below are the codes and screenshot of firestore:
List<dynamic> reviewsList = [];
Future _getReviews() async{
firestore.collection('shops').doc(widget.shop.id).collection('reviews').get()
.then((reviews){
reviews.docs.forEach((result) {
firestore.collection('shops').doc(widget.shop.id).collection('reviews').doc(result.id)
.get().then((reviewDocumentSnapshot) {
// To add to List //
});
});
});
}

the issue is related to misunderstanding of async. change your function as
Future _getReviews() async{
var reviews = await firestore.collection('shops').doc(widget.shop.id).collection('reviews').get();
reviews.docs.forEach((result) {
var reviewDocumentSnapshot= await firestore.collection('shops').doc(widget.shop.id).collection('reviews').doc(result.id);
//add this snapshot to list.
reviewsList[your_object.fromJson(reviewDocumentSnapshot)];
});
}
and your model class will be
class your_model {
String name;
String review;
int star;
String uid;
your_model({this.name, this.review, this.star, this.uid});
your_model.fromJson(Map<String, dynamic> json) {
name = json['name'];
review = json['review'];
star = json['star'];
uid = json['uid'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['review'] = this.review;
data['star'] = this.star;
data['uid'] = this.uid;
return data;
}
}

Related

How to append 2 Future lists into one in Dart?

I am new to Dart and relatively new to coding. I would appreciate some advice on this.
I have 2 api calls and I would like to merge their results into a single list. I am still trying to grasp the concepts of futures, so far I have understood that I can't just add the returned lists. Here's my code:
class ApiClient {
final Client _client;
ApiClient(this._client);
dynamic get(String path) async {
final response = await _client.get(
Uri.parse(
'${ApiConstants.BASE_URL}$path?api_key=${ApiConstants.API_KEY}'),
headers: {
'Content-Type': 'application/json',
},
);
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception(response.reasonPhrase);
}
}
}
class ResultsModel1{
List<Model1>? names;
ResultsModel1({this.names});
ResultsModel1.fromJson(Map<String, dynamic> json) {
if (json['results'] != null) {
names = <Model1>[];
json['results'].forEach((v) {
names!.add(Model1.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (names != null) {
data['results'] = names!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Model1{
final int id;
final int name;
const Model1({required this.id, required this.name});
factory Model1.fromJson(Map<String, dynamic> json){
return Model1(
id: json['id'],
name: json['name'],
);
}
Map<String, dynamic> toJson(){
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
return data;
}
}
class ResultsModel2{
List<Model2>? titles;
ResultsModel2({this.titles});
ResultsModel2.fromJson(Map<String, dynamic> json) {
if (json['results'] != null) {
titles = <Model2>[];
json['results'].forEach((v) {
titles!.add(Model2.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (titles != null) {
data['results'] = titles!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Model2{
final int id;
final int name;
const Model2({required this.id, required this.title});
factory Model2.fromJson(Map<String, dynamic> json){
return Model2(
id: json['id'],
name: json['name'],
);
}
Map<String, dynamic> toJson(){
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
return data;
}
}
abstract class API1{
Future<List<Model1>> getModel1();
}
class API1Imp extends API1{
final ApiClient _client;
API1Imp(this._client);
#override
Future<List<Model1>> getModel1() async{
final response = await _client.get('/baseurlextension');
final names = ResultsModel1.fromJson(response).names;
return names ?? [];
}
}
abstract class API2{
Future<List<Model2>> getModel2();
}
class API2Imp extends API2{
final ApiClient _client;
API2Imp(this._client);
#override
Future<List<Model2>> getModel2() async{
final response = await _client.get('/baseurlextension');
final titles = ResultsModel2.fromJson(response).titles;
return titles ?? [];
}
}
I want to finally get a new list let's say ObjectModel[id, title] where model2 is appended below model1
class ObjectImpl {
final API1Imp api1;
final API2Imp api2;
ObjectImpl(this.api1, this.api2);
#override
List<ObjectModel>>> getObject() async {
try {
final names = await API1Imp.getModel1();
final titles = await API2Imp.getModel2();
final objects = names + titles;
return objects;
}
}
}
but I guess it doesn't work like that. Can anyone please help out?
When using the + operator you can't merge two different list types.
When does it like:
final names = await API1Imp.getModel1();
final titles = await API2Imp.getModel2();
final objects = names + titles;
it will give you an error because it's a different type.
instead, you can do it like
final names = await API1Imp.getModel1();
final titles = await API2Imp.getModel2();
final objects = [...names ,...titles];
If you want names and titles to be in the same list just do this:
final objects = [...names, ...titles];
Otherwise, you need to process them individually to add titles to names like so:
final objects = [];
for (int i = 0; i < names.length; i++) {
objects.add('${names[i]} ${titles[i]}');
}
If you want something other than this, then provide some examples so that we understand exactly what you want.
but I guess it doesn't work like that
Instead, it does! It all comes down on your data structure and on what you want to achieve.
You can merge lists with the + operator, but the two list types must match (e.g. you can do [1,2,3] + [4,5,6] obtaining a List<int>, but you can't do add ['a','b','c'] like that).
You can obtain a List<Object> - if that's what you want - using the spread operator like this:
final futureListOne = Future.delayed(Duration(milliseconds: 750), () => [1,2,3]);
final futureListTwo = Future.delayed(Duration(milliseconds: 950), () => ['a','b','c']);
final listOne = await futureListOne;
final listTwo = await futureListTwo;
final mergedList = [...listOne, ...listTwo];
print(mergedList); // [1, 2, 3, a, b, c]
But is having a List<Object> desirable in your use case? That depends on what you need. Usually, having loose types around your code makes it less readable / reusable, but it really depends on the context.
Note. We can use Future.wait to await for both the futures in parallel and increase efficiency.
final lists = await Future.wait([futureListOne, futureListTwo]);
final listOne = lists[0];
final listTwo = lists[1];
Hope this helps.
Thanks everyone for the answers. After some struggle it worked like this
final names = await API1Imp.getModel1();
final titles = await API2Imp.getModel2();
final objects = [...names ,...titles];

how to send list<dynamic> to flutter firestore

I have marge one list (test1) with other list (test2) and got list dynamic (marge1), I need to convert marge1 to Map<String, dynamic> to send it to firestore, so far I understand. But I became stuck. What will be the solution. My code are as follows:
margeFunction() {
List test1 = [
{
"id": 0,
"name": customerName,
"address": customerAddress,
"mobile": customerMobile,
"deliveryDate": selectedDate1,
},
];
test1.forEach((element) {
test2.forEach((e) {
if (e["id"] == element["id"]) {
marge1.add(getmarge1(
e["id"],
e["itemName"],
e["description"],
e["itemPrice"],
e["image"],
e["unit"],
e["selectedServiceInList"],
e["uniqueListItem"],
e["subTotalListItem"],
e["counter"],
element["name"],
element["address"],
element["mobile"],
element["deliveryDate"],
));
}
});
});
}
Map<String, dynamic> getmarge1(
int id,
String itemName,
String description,
String itemPrice,
String image,
String unit,
String selectedServiceInList,
String uniqueListItem,
int subTotalListItem,
int counter,
String name,
String address,
String mobile,
DateTime deliveryDate) {
final Map<String, dynamic> data = new Map<String, dynamic>();
data["id"] = id;
data["itemName"] = itemName.toString();
data["description"] = description.toString();
data["itemPrice"] = itemPrice.toString();
data["image"] = image.toString();
data["unit"] = unit.toString();
data["selectedServiceInList"] = selectedServiceInList.toString();
data["uniqueListItem"] = uniqueListItem.toString();
data["subTotalListItem"] = subTotalListItem.toString();
data["counter"] = counter.toString();
data["name"] = name.toString();
data["address"] = address.toString();
data["mobile"] = mobile.toString();
data["deliveryDate"] = deliveryDate.toString();
return data;
}
Now I need to send the merge1 list to firestore. I have tried but can't figured it out. Any help is appreciated.
marge1 is a List<Map<String, dynamic>> and you'll want to write each of the Map<String, dynamic> item and not convert the list itself to a Map<String, dynamic>.
You will need to use a batched write.
Batched Writes: a batched write is a set of write operations on one or
more documents.
Source
You can do that as shown below:
final FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
final WriteBatch writeBatch = firebaseFirestore.batch();
final CollectionReference collectionReference = firebaseFirestore.collection("collectionPath");
marge1.forEach((element) {
final DocumentReference documentReference = collectionReference.doc();
writeBatch.set(documentReference, element);
});
writeBatch.commit();
Checkout FlutterFire's BatchedWrite documentation

Flutter get value in object list

In my Home.dart
static _getList() async {
Network network = Network();
final List list = await network.getData();
print("jsonString");
print(list);
return list;
}
Result in console:
flutter: [{id: 1, calc: 000100, name: Test, date: 2018-03-29 12:45:26.9830000}]
I need to get the id's and names of this object and generate a list, to be read
You need to convert your json data to objects.
There are tools to help you generating object from json like json2Dart. The result is :
class MyObject {
int id;
String calc;
String name;
String date;
MyObject({this.id, this.calc, this.name, this.date});
MyObject.fromJson(Map<String, dynamic> json) {
id = json['id'];
calc = json['calc'];
name = json['name'];
date = json['date'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['calc'] = this.calc;
data['name'] = this.name;
data['date'] = this.date;
return data;
}
#override
String toString() {
return '$id';
}
}
You need to iterate over your list from getData() and call MyObject.fromJson() from each occurence :
var myObjetcs = [];
for (var item in list) {
myObjetcs.add(MyObject.fromJson(item));
}
//Now, do what you want with myObjects
Hope it will help you

Unable to access list item inside a class

I've been wrapping my head around this issue for the past 2 hours (keep in mind that I'm new to Flutter). I'm trying to check if I've set up everything properly for getting a movie list from OMDB. Everything seems okay except the fact that I don't know how to access something inside a list ie. originalTitle.
This is the model:
class MovieItem {
int page;
int totalResults;
int totalPages;
List<Results> results;
MovieItem({this.page, this.totalResults, this.totalPages, this.results});
MovieItem.fromJson(Map<String, dynamic> json) {
page = json['page'];
totalResults = json['total_results'];
totalPages = json['total_pages'];
if (json['results'] != null) {
results = new List<Results>();
json['results'].forEach((v) {
results.add(new Results.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['page'] = this.page;
data['total_results'] = this.totalResults;
data['total_pages'] = this.totalPages;
if (this.results != null) {
data['results'] = this.results.map((v) => v.toJson()).toList();
}
return data;
}
}
class Results {
String posterPath;
int id;
String originalLanguage;
String originalTitle;
String title;
Results(
{this.posterPath,
this.id,
this.originalLanguage,
this.originalTitle,
this.title,});
Results.fromJson(Map<String, dynamic> json) {
posterPath = json['poster_path'];
id = json['id'];
originalLanguage = json['original_language'];
originalTitle = json['original_title'];
title = json['title'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['poster_path'] = this.posterPath;
data['id'] = this.id;
data['original_language'] = this.originalLanguage;
data['original_title'] = this.originalTitle;
data['title'] = this.title;
return data;
}
}
You are attempting to call a property on a List<Result> instead of Result. The property you are attempting to access exists on Result ... if there is a List of Result objects, what do you expect to return with movieItem.results.originalTitle? There could be any number of Result object with possibly different titles? If you just want to print them all out:
Future<MovieItem> movieItem() async {
var movieItem = await
client.movieItem();
movieItem.results.forEach((result) => print(result.originalTitle));
return movieItem;
}
The forEach will allow you to call the property and print it on every Result in the list
Your movieItem model class has list of result objects. So when you call the client.movieItem method the you get a MovieItem Object, and it you want to print the specific result item then just do this
print(movieItem.results[0].originalTitle)
and if you want to access all the objects from the result list then using for loop you can achieve it
for(int i=0;i<movieItem.results.length;i++)
{
print(movieItem.results[i].originalTitle);
}

flutter add data to json only if it does not already exist

I have following Model
product_model.dart
class ProductModel {
String status;
String message;
List<Results> results;
ProductModel({this.status, this.message, this.results});
ProductModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
message = json['message'];
if (json['data'] != null) {
results = new List<Results>();
json['data'].forEach((v) {
results.add(new Results.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['message'] = this.message;
if (this.results != null) {
data['data'] = this.results.map((v) => v.toJson()).toList();
}
return data;
}
}
class Results {
String id;
String productCode;
String category;
String title;
String isActive;
Results(
{this.id,
this.productCode,
this.category,
this.title,
this.isActive,
});
Results.fromJson(Map<String, dynamic> json) {
id = json['id'];
productCode = json['product_code'];
category = json['category'];
title = json['title'];
isActive = json['is_active'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['product_code'] = this.productCode;
data['title'] = this.title;
data['category'] = this.category;
data['is_active'] = this.isActive;
return data;
}
}
I have a functionality to save products to favorites. The favorites will be saved as json in a file.
import 'package:example/utils/favstorage.dart';
import 'package:example/models/product_model.dart';
class FavoriteProducts {
FavoritesStorage storage = FavoritesStorage();
List<ProductModel> favorites = [];
Future addFavorite(ProductModel products) async {
favorites.add(products);
await storage.writeFavorites(favorites);
}
}
I want to add product to favorites only if its not there. How can I update the addFavorite method so that if particular id doesnot exist then only proceed adding to favorites.
I am new to flutter. Can anybody help me on this??
You can use and indexWhere to search your list for an item with the same id, like this:
Future addFavorite(ProductModel products) async {
if(favorites.indexWhere((listProduct) => listProduct.id == products.id) == -1){
favorites.add(products);
await storage.writeFavorites(favorites);
}
}
-1 means there was no item, if there was the item it would have returned it from the list.
Understanding your model:
ProductModel has List
Results has id.
How to see if provided ProductModel can be added to favorite:
Take favorites list and look in List.
in each product model liik in List.
for each Results check if there id is same as any Results in List of provided ProductModel to the method.
If every thing is false, add ProductModel to favorite.
Following is the code for your reference:
Future addFavorite(ProductModel products) async {
bool containsId = favorites.any((ProductModel model){
return model.results.any((Results result){
return products.results.any((Results resultInProducts) => resultInProducts.id == result.id);
});
});
if(!containsId){
favorites.add(products);
await storage.writeFavorites(favorites);
}
}
I hope this helps, in case of any doubt please comment. If this answer helps you then please accept and up-vote the answer.