FireStore and Flutter - dart

I am writing an android app with flutter and Firestore at the backend database.
I can add single data to Firestore, but when I add an object with the nested object it fails. can't find any example or solution on google.
please help.
below is my code,
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:json_annotation/json_annotation.dart';
part 'Inspection.g.dart';
//run code => flutter packages pub run build_runner build
#JsonSerializable()
class Inspection extends Object with _$InspectionSerializerMixin {
Inspection(
{this.inspectionDate,
this.staffName,
this.arrivedTime,
this.leaveTime,
this.foundLocation,
this.postName,
this.guestsProportion,
this.situationRemark,
this.userid,
this.id,
this.grooming});
String id;
#JsonSerializable(nullable: false)
DateTime inspectionDate;
#JsonSerializable(nullable: false)
String arrivedTime;
#JsonSerializable(nullable: false)
String leaveTime;
#JsonSerializable(nullable: false)
String staffName;
#JsonSerializable(nullable: false)
String postName;
#JsonSerializable(nullable: false)
String foundLocation;
#JsonSerializable(nullable: false)
String guestsProportion;
#JsonSerializable(nullable: false)
String situationRemark;
#JsonKey(nullable: false)
String userid;
#JsonKey(nullable: false)
Grooming grooming;
static Inspection fromDocument(DocumentSnapshot document) =>
new Inspection.fromJson(document.data);
factory Inspection.fromJson(Map<String, dynamic> json) =>
_$InspectionFromJson(json);
}
#JsonSerializable()
class Grooming extends Object {
int groomingScore;
int hairScore;
int uniformScore;
int decorationScore;
int maskWearScore;
int maskCleanScore;
Grooming();
factory Grooming.fromJson(Map<String, dynamic> json) =>
_$GroomingFromJson(json);
}
and this is generated by build_runner
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'Inspection.dart';
// **************************************************************************
// Generator: JsonSerializableGenerator
// **************************************************************************
Inspection _$InspectionFromJson(Map<String, dynamic> json) => new Inspection(
inspectionDate: json['inspectionDate'] == null
? null
: DateTime.parse(json['inspectionDate'] as String),
staffName: json['staffName'] as String,
arrivedTime: json['arrivedTime'] as String,
leaveTime: json['leaveTime'] as String,
foundLocation: json['foundLocation'] as String,
postName: json['postName'] as String,
guestsProportion: json['guestsProportion'] as String,
situationRemark: json['situationRemark'] as String,
userid: json['userid'] as String,
id: json['id'] as String,
grooming: new Grooming.fromJson(json['grooming'] as Map<String, dynamic>));
abstract class _$InspectionSerializerMixin {
String get id;
DateTime get inspectionDate;
String get arrivedTime;
String get leaveTime;
String get staffName;
String get postName;
String get foundLocation;
String get guestsProportion;
String get situationRemark;
String get userid;
Grooming get grooming;
Map<String, dynamic> toJson() => <String, dynamic>{
'id': id,
'inspectionDate': inspectionDate?.toIso8601String(),
'arrivedTime': arrivedTime,
'leaveTime': leaveTime,
'staffName': staffName,
'postName': postName,
'foundLocation': foundLocation,
'guestsProportion': guestsProportion,
'situationRemark': situationRemark,
'userid': userid,
'grooming': grooming
};
}
Grooming _$GroomingFromJson(Map<String, dynamic> json) => new Grooming()
..groomingScore = json['groomingScore'] as int
..hairScore = json['hairScore'] as int
..uniformScore = json['uniformScore'] as int
..decorationScore = json['decorationScore'] as int
..maskWearScore = json['maskWearScore'] as int
..maskCleanScore = json['maskCleanScore'] as int;
abstract class _$GroomingSerializerMixin {
int get groomingScore;
int get hairScore;
int get uniformScore;
int get decorationScore;
int get maskWearScore;
int get maskCleanScore;
Map<String, dynamic> toJson() => <String, dynamic>{
'groomingScore': groomingScore,
'hairScore': hairScore,
'uniformScore': uniformScore,
'decorationScore': decorationScore,
'maskWearScore': maskWearScore,
'maskCleanScore': maskCleanScore
};
}
code used to insert data
Future<bool> addInspection(Inspection item) async {
print('creating');
var newdoc = await inspectionCollection.document().get();
item.id = newdoc.documentID;
item.userid = user.uid;
inspectionCollection.add(item.toJson()).then((onValue) {
onValue.setData({'id': onValue.documentID});
}).catchError((error) {
print(error.toString());
});

Related

Error in parsing nested JSON list in flutter

Calling API but showing error, I'm unable to parse data in the bean class.
My Response:
{
"error":"0",
"status":200,
"deliveryCharge":"14.00",
"image_base_url":"http:\/\/xxxxx.tk\/assets\/event\/image\/",
"image_logo_url":"http:\/\/xxxxx.tk\/assets\/event\/logo\/",
"eventList":[
{
"event_id":"1",
"event_name":"Syscraft Premier League",
"event_location":"12 ny valleys",
"event_type_id":"15",
"start_date":"2019-01-10 03:21:00",
"end_date":"2019-01-26 16:10:00",
"event_logo":"f4f0bfc168a3816891e2749232c5243f.jpg"
},
{
"event_id":"3",
"event_name":"Republic Day Event 2019",
"event_location":"AH-654 Villa No. 42 New Township New Township",
"event_type_id":"1",
"start_date":"2019-01-26 00:00:00",
"end_date":"2019-01-26 11:55:00",
"event_logo":"3a4a7fabbbd7ed8febf67bacda71ae48.jpg"
}
]
}
Calling Api
Future<List<EventResponse>> fetchEvent( ) async {
String url='http://xxxxxxxxxxxxxxx.tk/api/userapp/event/lists';
var headers = new Map();
headers['Auth-Key'] = 'OCDOC#2018';
headers['End-Client'] = 'OCDOC';
var body = new Map();
headers['schedule'] = 'present';
http.Response res = await http.post(url,headers: headers, body: body);
final Map<String,dynamic> parsed=json.decode(res.body); // post api call
print("Reposnce Event:---"+parsed.toString());}
My Bean class
class EventResponse{
String error;
int status;
String deliveryCharges;
String imageBaseUrl;
String imageLogoUrl;
List<Event> eventList;
EventResponse({
this.error,
this.status,
this.deliveryCharges,
this.imageBaseUrl,
this.imageLogoUrl,
this.eventList
});
factory EventResponse.convertEventResponse(Map<String,dynamic> json){
return EventResponse(
error: json['error'],
status: json['status'],
deliveryCharges: json['deliveryCharge'],
imageBaseUrl: json['image_base_url'],
imageLogoUrl: json['image_logo_url'],
eventList: json['eventList']);
}}
class Event{
String eventId;
String eventName;
String location;
String event_logo;
Event({
this.eventId,
this.eventName,
this.location,
this.event_logo,
});
factory Event.convertEvent(Map<String,dynamic> json){
return Event(
eventId: json['event_id'],
eventName: json['event_name'],
location: json['event_location'],
event_logo: json['event_logo'],
);}}
Showing Error
_InternalLinkedHashMap<dynamic, dynamic> is not a subtype of type Map<String, String>
Rewrite EventResponse like this:
class EventResponse {
String error;
int status;
String deliveryCharges;
String imageBaseUrl;
String imageLogoUrl;
List<Event> eventList;
EventResponse(
{this.error,
this.status,
this.deliveryCharges,
this.imageBaseUrl,
this.imageLogoUrl,
this.eventList});
factory EventResponse.convertEventResponse(Map<String, dynamic> json) {
List<dynamic> events = json['eventList'];
List<Event> eventList = events.map((e) => Event.convertEvent(e)).toList();
return EventResponse(
error: json['error'],
status: json['status'],
deliveryCharges: json['deliveryCharge'],
imageBaseUrl: json['image_base_url'],
imageLogoUrl: json['image_logo_url'],
eventList: eventList,
);
}
}
I have changed EventResponse as #Richard Heap did.
factory EventResponse.convertEventResponse(Map<String, dynamic> json) {
List<dynamic> events = json['eventList'];
List<Event> eventList = events.map((e) => Event.convertEvent(e)).toList();
return EventResponse(
error: json['error'],
status: json['status'],
deliveryCharges: json['deliveryCharge'],
imageBaseUrl: json['image_base_url'],
imageLogoUrl: json['image_logo_url'],
eventList: eventList,
);
}
}
One more thing I need to change is when I post parameters and headers need to define their Map() to Map<String,String>().
Future<EventResponse> fetchEvent( ) async { // here i change Future type
String url='http://xxxxxxx-oceanapparel.tk/api/userapp/event/lists';
var headers = new Map<String, String>(); //here i defined Map type
headers['Auth-Key'] = 'OCDOC#2018';
headers['End-Client'] = 'OCDOC';
var body = new Map<String, String>(); //here i defined Map type
headers['schedule'] = 'present';
http.Response res = await http.post(url,headers: headers, body: body);
print("Reposnce Event:---"+res.body);
}

Convert a class into JSON or List

How to convert this class into JSON or List?
class cliente {
int id;
String nome;
String apelido;
String sexo;
String status;
}
Edit
I'm changed my class and works fine to my case:
class client {
Map<String, dynamic> fields => {
"id": "",
"name": "",
"nickname": "",
"sex": "",
"status": "",
}
Then I use:
client.fields["id"] = 1;
client.fields["name"] = "matheus";
sqlite.rowInsert("insert into client(id, name)", client.fields.Keys.toList(), client.fields.Values.toList());
Just create a method inside your class and return a Map<String, dynamic>
class cliente {
int id;
String nome;
String apelido;
String sexo;
String status;
Map<String, dynamic> toJson() => {
'id': id,
'nome': nome,
'apelido': apelido,
'sexo': sexo,
'status': status,
};
}
And use it for example :
final dataObject = new client();
...fill your object
final jsonData = dataObject.toJson();
Also you can try using this package to avoid writing all of your fields : https://pub.dartlang.org/packages/json_serializable

Flutter Firestore Server side Timestamp

I need to add a server side timestamp on new documents added to Firestore using a Flutter app. I see I am supposed to use FieldValue.serverTimestamp but I am not sure where to find this.
As of September 5th, the updated cloud_firestore v0.8.0 library now has FieldValue.serverTimestamp(). All is now well in the universe
'timestamp' : Timestamp.now()
Timestamp.now() is part of cloud_firestore;
Example
Screenshot showing that the library is imported from cloud_firestore, and creates a server-generated timestamp in the written data. Docs
Expanding on #spongyboss' answer (which works as of April 2020) by adding sample usage:
_firestore.collection('messages').add({
'text': messageText,
'sender': loggedInUser.email,
'created': FieldValue.serverTimestamp()
});
'created' will be stored as a timestamp
Sample sorting:
_firestore.collection('messages')
.orderBy('created', descending: false)
.snapshots()
If you are using a model class to set the data, then you should create a dynamic variable with some name. For mine it was 'createdDate'.
class Products {
Products({
this.data,
this.createdDate,
});
List<ProductItems>? data;
dynamic createdDate;
factory Products.fromJson(Map<String, dynamic> json) => Products(
data: List<ProductItems>.from(json["data"].map((x) => ProductItems.fromJson(x))),
createdDate: json["createdDate"],
);
Map<String, dynamic> toJson() => {
"data": List<dynamic>.from(data!.map((x) => x.toJson())),
"createdDate": createdDate
};
}
class ProductItems {
String? id;
String? name;
int? price;
int? quantity;
ProductItems({
this.price,
this.quantity,
this.name,
this.id,
});
ProductItems.fromJson(Map<String, dynamic> json) {
price = json['price'];
quantity = json['quantity'];
name = json['name'];
id = json['id'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['price'] = price;
data['quantity'] = quantity;
data['name'] = name;
data['id'] = id;
return data;
}
}
And during setting the data to firestore,
final CollectionReference _cart = _firestore.collection('cart');
final _cartReference = _cart.withConverter<Products>(
fromFirestore: (snapshot, _) => Products.fromJson(snapshot.data()!),
toFirestore: (userModel, _) => userModel.toJson(),
);
await _cartReference.doc(auth?.uid).set(Products(
data: productList.data,
createdDate: FieldValue.serverTimestamp(),
));

Dart - How can I Map String & Int together?

static Future<String> compress({#required String imageSrc, #required int desiredQuality}) async {
final Map<String, dynamic> params = <String, dynamic> {
'filePath': imageSrc.toString()
};
I'm trying to add desiredQuality on the "params" map, but that's an int, how can I do it?
EDIT:
Turns out I didn't need to map int, all I had to do was this:
static Future<String> compress({#required String imageSrc, #required int desiredQuality}) async {
final Map<String, dynamic> params = <String, dynamic> {
'filePath': imageSrc,
'desiredQuality': desiredQuality
};
Thanks to #MarcG and #Gunter
A Map object could contain a collection of key/value pairs. Since you're trying to assign imageSrc (String) and desiredQuality (int) values on a Map<String, dynamic>, you can assign keys for each of these values in the Map.
Map<String, dynamic> params = {
'filePath': imageSrc,
'desiredQuality': desiredQuality
};
To access these key/values set in the Map, you can call them using:
var filePath = params['filePath'];
var desiredQuality = params['desiredQuality'];

Dart Convert List as Map Entry for JSON Encoding

I asked a question before about Dart encoding/decoding to JSON, however, the libraries that were suggested were not complete and I decided to manually handle that.
The objective is to convert these objects to a map.
class Parent extends Object {
int id;
String name;
List<Child> listChild = new List<Child>();
Map toMap() => {"id":id, "name":name, "listChild":listChild};
}
class Child extends Object {
int id;
String childName;
Map toMap() => {"id":id, "childName":childName};
}
When doing
print(JSON.encode(parent.toMap()));
I am seeing it go here, any suggestion how to make this work?
if (!stringifyJsonValue(object)) {
checkCycle(object);
try {
var customJson = _toEncodable(object);
if (!stringifyJsonValue(customJson)) {
throw new JsonUnsupportedObjectError(object);
}
_removeSeen(object);
} catch (e) {
throw new JsonUnsupportedObjectError(object, cause : e);
}
}
}
Map toMap() => {"id":id, "name":name: "listChild": listChild.map((c) => c.toJson().toList())};
is valid for JSON.
import 'dart:convert' show JSON;
...
String json = JSON.encode(toMap());
You can also use the toEncodeable callback - see How to convert DateTime object to json
If your class structure does not contain's any inner class then follow
class Data{
String name;
String type;
Map<String, dynamic> toJson() => {
'name': name,
'type': type
};
}
If your class uses inner class structure
class QuestionTag {
String name;
List<SubTags> listSubTags;
Map<String, dynamic> toJson() => {
'name': name,
'listSubTags': listSubTags.map((tag) => tag.toJson()).toList()
};
}
class SubTags {
String tagName;
String tagDesc;
SubTags(this.tagName, this.tagDesc);
Map<String, dynamic> toJson() => {
'tagName': tagName,
'tagDesc': tagDesc,
};
}
Just rename Map toMap() into Map toJson() and it will work fine. =)
void encode() {
Parent p = new Parent();
Child c1 = new Child();
c1 ..id = 1 ..childName = "Alex";
Child c2 = new Child();
c2 ..id = 2 ..childName = "John";
Child c3 = new Child();
c3 ..id = 3 ..childName = "Jane";
p ..id = 1 ..name = "Lisa" ..listChild = [c1,c2,c3];
String json = JSON.encode(p);
print(json);
}
class Parent extends Object {
int id;
String name;
List<Child> listChild = new List<Child>();
Map toJson() => {"id":id, "name":name, "listChild":listChild};
}
class Child extends Object {
int id;
String childName;
Map toJson() => {"id":id, "childName":childName};
}

Resources