Flutter data to Json - firebase

How can I transfer QuerySnapshot object data from Firebase to JSON string?
Do I need to use
json.decode(qs)?
Thank you

1, Recommend you to use pkg: json_annotation to define model.
https://flutter.dev/docs/development/data-and-backend/json
2, When define model, let using bellow annotation for your model :
import 'package:json_annotation/json_annotation.dart';
part 'agent.g.dart';
#JsonSerializable(
anyMap: true
)
class Agent {
#JsonKey(
ignore: true
)
String id;
String name;
String avatar;
String email;
String phone;
String team;
String password;
Agent(this.name, this.avatar, this.email, this.phone, this.team, this.password);
factory Agent.fromJson(Map<String, dynamic> json) => _$AgentFromJson(json);
Map<String, dynamic> toJson() => _$AgentToJson(this);
}
3, Parser model with documentSnapshot:
Agent.fromJson(documentSnapshot.data)

Related

Two Object in Firestore Referencing each other

I have 2 object stored in Firestore Product & Shop
And there maybe a lot of Product and Shop in the future, so I have Shop DocumentReference in Product and vise-versa
Here are how they look like
class Shop extends Equatable {
final String? id;
final String name;
final List<Product?> shopProduct;
final DateTime createDate;
...
static Future<Shop> fromDocument(DocumentSnapshot doc) async {
final data = doc.data() as Map<String, dynamic>;
final shopProductRef = data['shopProduct'];
final List<Product?> shopProductList;
if (shopProductRef.isNotEmpty) {
shopProductList = List.from(shopProductRef.map((ref) async {
Product.fromDocument(await ref!.get());
}));
} else {
shopProductList = [];
}
return Shop(
id: doc.id,
name: data['name'],
shopProduct: shopProductList,
createDate: (data['createDate'] as Timestamp).toDate(),
);
}
And
class Product extends Equatable {
final String? id;
final Shop shop;
final double price;
final String title;
final DateTime date;
...
static Future<Product?> fromDocument(DocumentSnapshot doc) async {
final data = doc.data() as Map<String, dynamic>;
final shopRef = data['shop'] as DocumentReference;
final shopDoc = await shopRef.get();
return Product(
id: doc.id,
shop: await Shop.fromDocument(shopDoc),
price: data['price'],
title: data['title'],
date: (data['date'] as Timestamp).toDate(),
);
}
This is what I think should work in the first place but it brings up a problem that it is causing a loop since both are referencing each other.
I have come up a fix which is creating a second fromDocument method which skip the shopProduct or Shop when I am referencing it.
Is it the only / best way to do it?
Thank you
As I know you have two options
First one is to add a document reference instead of referring to the classes
something like this
class Product extends Equatable {
final String? id;
final DocumentRefrence<Shop> shop;
final double price;
final String title;
final DateTime date;
...
and also do the same for Shop model
class Shop extends Equatable {
final String? id;
final String name;
final List<DocumentReference<Product>?> shopProduct;
final DateTime createDate;
...
Second one is as you mentioned, create a method for Product model and name it for example: Map<String, dynamic> toShopCollection() and use it while setting a shop in firestore and also do the same for Shop model.
cm if you need more details

#JsonKey how to access to elements of a Map, flutter

I have the next map config, I was wondering how I could access to it using the #JsonKey keyword.
import 'package:json_annotation/json_annotation.dart';
part 'user_model.g.dart';
#JsonSerializable()
class UserModel {
#JsonKey(name: 'username')
String username;
#JsonKey(name: 'realName')
String realname;
#JsonKey(name: 'gender')
String gender;
#JsonKey(name: 'date_birth')
String dateBirth;
#JsonKey(name: 'isObserver')
bool isObserver;
#JsonKey(name: 'friends')
List<dynamic> friendsList;
#JsonKey(name: 'pendingFriends')
List<dynamic> pendingFriendsList;
#JsonKey(name: 'config') // Here, config is a map, how can I access to their data?
bool notifyFriend;
UserModel(this.username, this.realname, this.dateBirth, this.gender,
this.isObserver, this.friendsList, this.pendingFriendsList, this.notifyFriend);
factory UserModel.fromJson(Map<String, dynamic> json) =>
_$UserModelFromJson(json);
Map<String, dynamic> toJson() => _$UserModelToJson(this);
}
First of all you have to create another class with the name config having those 3 variables in it and then import that class in this class and replace the variable there with that like :
class Config{
#JsonKey(name: 'notifyFriends')
bool notifyFriend;
#JsonKey(name: 'recordAudio')
bool recordAudio;
#JsonKey(name: 'sendTweet')
bool sendTweet;
Config(this.sendTweet, this.recordAudio, this.notifyFriend);
factory Config.fromJson(Map<String, dynamic> json) =>
_$ConfigFromJson(json);
Map<String, dynamic> toJson() => _$ConfigToJson(this);
}
and use it like this:
#JsonKey(name: 'config') // Here,
Config config;
I hope this clear your problem.

Adding collection and subcollection data to model entity from firestore firebase

I'm recently started using Firebase firestore. I'm stuck at the point were the collection have sub collections and get those items to my model.
Let say I have this collection
meats
\ id : 1
\ name : Chicken
subMeats
\ id : 11
\ name : Country Chicken
\ id : 12
\ name : Broiler Chicken
meats
\ id : 2
\ name : Pork
subMeats
\ id : 21
\ name : White Pork
\ id : 22
\ name : Black Pork
return meatTypeCollection.get().then((value) {
value.docs.forEach((mainDoc) {
// MainMeatEntity.fromSnapshot(mainDoc)
_logger.i(mainDoc.data()['name']);
meatTypeCollection
.doc(mainDoc.id)
.collection('subMeats')
.get()
.then((snapShots) {
snapShots.docs.forEach((doc) {
_logger.i(doc.data()['name']);
MainMeat.fromEntity(MainMeatEntity.fromSnapshot(doc));
});
});
});
//return MeatTypes.fromEntity(MeatTypeEntity.fromJson(value.docs));
}).catchError((error) => _logger.e("Failed to load meat types : $error"));
The above does not capture the collection. I use entity to model.
import 'package:flutter/cupertino.dart';
import 'entities/main_meat_entity.dart';
import 'entities/meat_type_entity.dart';
#immutable
class MainMeat {
final String id;
final String name;
final MeatTypeEntity subMeats;
final String shopId;
const MainMeat({
this.id,
this.name,
this.subMeats,
this.shopId,
});
static MainMeat fromEntity(MainMeatEntity mainMeatEntity) {
return MainMeat(
id: mainMeatEntity.id,
name: mainMeatEntity.name,
subMeats: mainMeatEntity.subMeats,
shopId: mainMeatEntity.shopId,
);
}
MainMeatEntity toEntity() {
return MainMeatEntity(id, name, subMeats, shopId);
}
static const empty = MainMeat(id: '', shopId: "", name: "");
}
-----------------------------****************--------------------
part 'meat_type_entity.g.dart';
#JsonSerializable()
class MeatTypeEntity extends Equatable {
final String id;
final String name;
final String shopId;
const MeatTypeEntity(this.id, this.name, this.shopId);
factory MeatTypeEntity.fromJson(Map<String, dynamic> json) =>
_$MeatTypeEntityFromJson(json);
Map<String, dynamic> toJson() => _$MeatTypeEntityToJson(this);
#override
List<Object> get props => [
id,
name,
shopId,
];
static MeatTypeEntity fromSnapshot(DocumentSnapshot snap) {
return MeatTypeEntity(
snap.id,
snap.data()['name'],
snap.data()["shopId"],
);
}
Map<String, Object> toDocument() {
return {
"id": id,
'mainMeat': name,
"shopId": shopId,
};
}
}
I can list it's collection and sub collections fine. But not sure to load into my model. Any help appreciated thanks.
You can't store subCollection to collection directly, Read FireStore data model section.
So your structure will be look like
Meal(document) -> all meal collection -> Sub Meal (document) -> all sub meals collection.
If you want to read the data like firebase database, you can't read the complete tree/hierarchy at a time.
So assuming this is a Dart question of how to create models, I would create something like this:
class Meat {
final String id;
final String name;
final List<SubMeat> subMeats;
Meat({
#required this.id,
#required this.name,
this.subMeats,
});
}
class SubMeat {
final String id;
final String name;
SubMeat({
#required this.id,
#required this.name,
});
}

Flutter-Firestore "The argument type 'Map<String, dynamic> Function()' can't be assigned to the parameter type 'Map<String, dynamic>"

I try to review my data inside firebase firestore. But this error is come inside my firestore_service.dart file.Can you help me solve this error.
"The argument type 'Map<String, dynamic> Function()' can't be assigned to the parameter type 'Map<String, dynamic>"
This is my firestore_service.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:esrimarket/note.dart';
import 'package:flutter/foundation.dart';
class FirestoreService {
static final FirestoreService _firestoreService =
FirestoreService._internal();
Firestore _db = Firestore.instance;
FirestoreService._internal();
factory FirestoreService() {
return _firestoreService;
}
getNotes(){
return _db
.collection('notes')
.snapshots()
.map((snapshot)=>snapshot.documents.map((doc)=>Note.fromMap(doc.data, doc.documentID)));
}
}
This is my note.dart file
class Note{
final String name;
final String price;
final String quantity;
final String id;
Note({this.name, this.price, this.quantity, this.id});
Note.fromMap(Map<String,dynamic> data, String id):
name=data["name"],
price=data["price"],
quantity=data["quantity"],
id=id;
}
You are missing brackets after the member data because it's a function:
Note.fromMap(doc.data(), doc.documentID)
^^

The argument type 'Map<String, dynamic> Function()' can't be assigned to the parameter type 'Map<String, dynamic>'

This could initially was working but after firebase update, it is now giving me this error. I have added asterisks to the part giving the error. The error message has been added beneath the code.
import 'package:cloud_firestore/cloud_firestore.dart';
class Record {
final String name;
final int totalVotes;
final DocumentReference reference;
Record.fromMap(Map<String, dynamic> map, {this.reference})
: assert(map['name'] != null),
assert(map['totalVotes'] != null),
name = map['name'],
totalVotes = map['totalVotes'];
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(**snapshot.data**, reference: snapshot.reference);
#override
String toString() => "Record<$name:$totalVotes>";
}
class Voters {
String uid;
String voteId;
String markedVoteOption;
}
The argument type 'Map<String, dynamic> Function()' can't be assigned to the parameter type 'Map<String, dynamic>'.
Try the following:
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data(), reference: snapshot.reference);
data() is a method:
/// Contains all the data of this [DocumentSnapshot].
Map<String, dynamic> data() {
return _CodecUtility.replaceDelegatesWithValueInMap(
_delegate.data(), _firestore);
}
that returns a Map<String, dynamic>
It's because DocumentSnapshot.data() is a function that returns Map<String, dynamic>.
So, the answer is:
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data(), reference: snapshot.reference);
This works for me.
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data() as Map<String, dynamic>, reference: snapshot.reference);
Apparently all that was needed was parentheses on the maps
import 'package:cloud_firestore/cloud_firestore.dart';
class Record {
final String name;
final int votes;
final DocumentReference reference;
Record.fromMap(Map<String, dynamic> map(), {this.reference})
: assert(map()['name'] != null),
assert(map()['votes'] != null),
name = map()['name'],
votes = map()['votes'];
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, reference: snapshot.reference);
#override
String toString() => "Record<$name:$votes>";
}
This is how I solved it.
import 'package:cloud_firestore/cloud_firestore.dart';
class Record {
final String name;
final int totalVotes;
final DocumentReference reference;
Record.fromMap(Map<String, dynamic> map(), {this.reference})
: assert(map()['name'] != null),
assert(map()['totalVotes'] != null),
name = map()['name'],
totalVotes = map()['totalVotes'];
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, reference: snapshot.reference);
#override
String toString() => "Record<$name:$totalVotes>";
}
class Voters {
String uid;
String voteId;
String markedVoteOption;
}
/// Contains all the data of this [DocumentSnapshot].
Map<String, dynamic> data() {
return _CodecUtility.replaceDelegatesWithValueInMap(
_delegate.data(), _firestore);
}

Resources