Flutter Firestore: Building my model from a snapshot - firebase

I'm struggling to build my model from firestore map. It seems basic yet I can't figure it out.
Here's my code :
firestore_service.dart
{
// ...
final FirebaseFirestore _db = FirebaseFirestore.instance;
await _db
.collection('Users')
.doc('jWtp19r7g2b4wwMJ5yBi')
.get()
.then((snapshot) {
print(snapshot);
print(snapshot.runtimeType);
final _data = snapshot.data() ?? {};
print(_data);
print(_data['uid']);
final user = UserModel.fromJson(_data);
print(user.uid);
return user;
});
}
user_model.dart
import 'package:flutter/material.dart';
class UserModel {
// ...
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
uid: json['uid'],
username: json['username'],
characterID: json['character_id'],
);
}
}
Terminal
Can anyone help me?

Okay so, I don't know if it's a "clean" way of doing it but I figured I could add another factory in my model to build specifically from Firestore.
Since the specific error was Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<String>', I duckduckgo-ed the error and found this solution :
service.dart
await _db
.collection('Users')
.doc('jWtp19r7g2b4wwMJ5yBi')
.get()
.then((snapshot) {
final _data = Map<String, dynamic>.from(snapshot.data() ?? {});
print(_data.runtimeType);
final user = UserModel.fromFirestore(_data);
print(user.uid);
});
user_model.dart
class UserModel {
UserModel({
required this.uid,
required this.characterID,
this.username,
});
final String uid;
final String? username;
final List<String> characterID;
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
uid: json['uid'],
username: json['username'],
characterID: json['character_id'],
);
}
factory UserModel.fromFirestore(Map<dynamic, dynamic> json) {
return UserModel(
uid: json['uid'],
username: json['username'],
characterID: List<String>.from(json['character_id']),
);
}
Map<String, dynamic> toJson() => {
"uid": uid,
"username": username,
"character_id": characterID,
};
}
I feel like it's not my factory's role to "filter / cast" the data but that's the only way I found it working.

Related

Flutter How to model any class instead of FutureBuilder?

I have a model and I want to use my services file to fill it from Firebase but I don't know how to do that ?
I am filling it with FutureBuilder that's okey. But it is exhausting me.
Here is my model:
class ReviewModel {
String? uid;
String? userID;
String? comment;
dynamic rate;
ReviewModel({
this.uid,
this.userID,
this.comment,
this.rate,
});
Map<String, dynamic> toMap() {
return {
'uid': uid,
'userID': userID,
'comment': comment,
'rate': rate,
};
}
factory ReviewModel.fromMap(Map<String, dynamic> map) {
return ReviewModel(
uid: map['uid'],
userID: map['userID'],
comment: map['comment'],
rate: map['rate'],
);
}
factory ReviewModel.fromDatabase(
DocumentSnapshot snapshot, Map<String, dynamic> map) {
return ReviewModel(
uid: snapshot['uid'],
userID: map['userID'],
comment: map['comment'],
rate: map['rate'],
);
}
}
Code is Following below,
Future<ReviewModel> getSalonReviews(String salonUID) async {
CollectionReference aRef = FirebaseFirestore.instance
.collection("salons")
.doc(salonUID)
.collection('bucket')
.doc('reviewbox')
.collection('reviews');
dynamic _doc;
var snapshot;
try {
await aRef.get().then((querySnapshot) => {
for (var dummyDoc in querySnapshot.docs)
{
_doc = dummyDoc.data(),
print(_doc),
}
});
return ReviewModel.fromMap(_doc);
} on FirebaseException catch (e) {
Get.snackbar("Hata", e.code);
rethrow;
}
}
This code is not returning my ReviewModel.
Also I am using GetX and this is my GetX code:
final Rx<ReviewModel> _reviewModel = ReviewModel().obs;
ReviewModel get reviewModel => _reviewModel.value;
set reviewModel(ReviewModel value) => _reviewModel.value;
Future fillReviewModel(String uid) async {
SalonController.instance.reviewModel =
await FakeService().getSalonReviews(uid);
}
it return me this:
And this is my Firebase docs:
How do I achive my ReviewModel with Obx. If I try it, it returns null.
You don't have to return a model you'll do something like this in your prvoider file:
List _reviews = [];
List get reviews => [..._reviews];
// IN your future void function
Future<void> myFunction () async{
myReviews = ...result of forEach;
// now update _reviews
_reviews = [...myReviews];
//And then notify listeners
notifylisteners;
}
And then in your futurebuilder
FutureBuilder(future: Provider.of<myClass>(context, listen:false).myFunction(),
builder:(context, snapshot){
// check the state like the following
if(snapshot.connectionState == ConnectionState.done){
final myValues = Provider.of<myClass>(context, listen:false).reviews;
...do something
return your_values}
if(snapshot.connectionState == ConnectionState.waiting){return progressIndicator}
})

Flutter: _CastError (type 'Null' is not a subtype of type 'Map<String, dynamic>' in type cast)

When I create a new user the error (_CastError (type 'Null' is not a subtype of type 'Map<String, dynamic>' in type cast)) apears at User.fromSnap ...as Map<stringm,dynamic> and firebase creates the user auth but not the user data
Can you help me to add array of array of objects to firebase?
Thanks!
user.dart
class User {
final String uid;
final String name;
final List<Game> game;
User(
{required this.uid,
required this.name,
required this.game});
factory User.fromSnap(DocumentSnapshot snap) {
var snapShot = snap.data() as Map<String, dynamic>;
return User(
uid: snapShot['uid'],
name: snapShot['name'],
game: snapShot['game']);
}
Map<String, dynamic> toJson() => {
'uid': uid,
'name': name,
'game': game,
};
}
class Game{
String rolName;
bool alive;
Game({required this.rolName, required this.alive});
factory Game.fromSnap(Map<String, dynamic> snap) {
return Game(rolName: snap['rolName'], alive: snap['alive']);
}
}
auth.dart
class AuthMethods with ChangeNotifier {
...
Future<String> singUpUser(
{required String email,
required String password,
required String namee}) async {
String res = 'Error';
try {
if (email.isNotEmpty ||
password.isNotEmpty ||
name.isNotEmpty ) {
UserCredential cred = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
model.User _user = model.User(
uid: cred.user!.uid,
name: name,
game: [model.Game(rolName: 'default', alive: false)]);
await _firestore
.collection("users")
.doc(cred.user!.uid)
.set(_user.toJson());
res = 'success';
} else {
res = "Please enter all the fields";
}
} catch (err) {
res = err.toString();
}
return res;
}
Your factory looks right. But you're sending it nothing...the snap is null is what that error is telling you.

Flutter Assigning QuerySnapshot to Map<dynamic, dynamic>

I am trying to fetch some menu item details such as menu name, slogan text icon, and verify data from firebase firestore using flutter but in the services of database getMenus() function, I am facing an error.
I have the following class model
import 'dart:convert';
MenuModel medicalTestModelFromJson(String str) => MenuModel.fromJson(json.decode(str));
String medicalTestModelToJson(MenuModel data) => json.encode(data.toJson());
class MenuModel {
MenuModel({
required this.title,
required this.slogan,
required this.icon,
required this.verify,
});
String title;
String slogan;
String icon;
bool verify;
factory MenuModel.fromJson(Map<String, dynamic> json) => MenuModel(
title: json["title"],
slogan: json["slogan"],
icon: json["icon"],
verify: json["verify"],
);
Map<String, dynamic> toJson() => {
"title": title,
"slogan": slogan,
"icon": icon,
"verify": verify,
};
}
And the following is the menu collection services from firebase firestore
class MenuServices{
static Future<List<MenuModel>> getMenus() async {
QuerySnapshot menuSnapshot = await FirebaseFirestore.instance.collection('homeItems').where("verify", isEqualTo: true).get();
List<MenuModel> menus =[];
Map<dynamic, dynamic> values = menuSnapshot.docs; //(***My Error is Exactly in this line which menuSnapshot.docs is not recognizing***)
values.forEach((key, values) {
menus.add(MenuModel.fromJson(values));
});
return menus;
}
}
And the error is
A value of type 'List<QueryDocumentSnapshot<Map<String, dynamic>>>' can't be assigned to a variable of type 'Map<dynamic, dynamic>
Change it to this:
class MenuServices{
static Future<List<MenuModel>> getMenus() async {
QuerySnapshot menuSnapshot = await FirebaseFirestore.instance.collection('homeItems').where("verify", isEqualTo: true).get();
List<MenuModel> menus = menuSnapshot.docs.map(
(e)=> MenuModel.fromJson(e.data() as Map<String, dynamic>)).toList();
return menus;
}
}
I used this and it worked:
void getLeituras(QuerySnapshot snapshot){
List leituras = [];
Leitura leitura;
snapshot.docs.forEach((e) {
leitura = Leitura();
leitura = Leitura.fromJson(e.data as Map<String, dynamic>);
leituras.add(leitura);
});
}

How to store data into model using fromJson in flutter firebase?

Currently I'm working on a flutter project. I'm trying to create a function that gets snapshot from Firebase document and stores it into userData model using fromJson function.
Here's my User.dart
class UserData {
// final String uid;
final String usn;
final String fullName;
final int? sem;
final String branch;
final String section;
UserData({
required this.usn,
required this.fullName,
required this.sem,
required this.branch,
required this.section,
});
factory UserData.fromJson(Map<String, dynamic> json) {
return UserData(
usn: json['usn'],
fullName: json['fullName'],
sem: json['sem'],
branch: json['branch'],
section: json['section']);
}
Map<String, dynamic> toMap() {
return {
'usn': usn,
'fullName': fullName,
'sem': sem,
'branch': branch,
'section': section
};
}
}
In my database.dart
I want to create a Stream function in it to map to fromJson
Here's what I have tried
Stream<UserData?> curUserData() {
return _db.collection('users').doc(user.uid).snapshots()
.map((DocumentSnapshot snapshot) => UserData.fromJson(snapshot.data()));
}
Can anyone rectify the function?
I am getting error from above function.
Your problem is just wrong type assertion. Try this:
Change DocumentSnapshot for DocumentSnapshot<Map<String, dynamic>>
Stream<UserData?> curUserData() {
return _db.collection('users').doc(user.uid).snapshots()
.map((DocumentSnapshot<Map<String, dynamic>> snapshot) => UserData.fromDocument(snapshot.data()!));
}
This example is for my case with cloud_firestore: ^3.1.7:
getLastStageNumber() async {
QuerySnapshot querySnapshot = await stagesRef
.orderBy('stage_number', descending: true)
.limit(1)
.get();
StageMod stageMod;
if (querySnapshot.docs.isNotEmpty) {
stageMod = StageMod.fromJson(
querySnapshot.docs.first.data()! as Map<String, dynamic>);
lastStageNumber = stageMod.stageNumber;
}
}

The method 'document' isn't defined for the type 'CollectionReference'. Flutter/Firebase

The method 'document' isn't defined for the type 'CollectionReference'.
Try correcting the name to the name of an existing method, or defining a method named 'document'.
I am getting this error in my project. Can you help me?
My Code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:crypto_app/models/users.dart';
class FireStoreService {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final DateTime time = DateTime.now();
Future<void> createUser({id, mail, userName, photoUrl = ""}) async {
await _firestore.collection("users").doc(id).set({
"userName": userName,
"mail": mail,
"photoUrl": photoUrl,
"about": "",
"createTime": time
});
}
Future<Users> bringUser(id) async {
DocumentSnapshot doc = await _firestore.collection("users").doc(id).get();
if (doc.exists) {
Users users = Users.dokumandanUret(doc);
return users;
}
return null;
}
void userUpdate({String userId, String userName, String photoUrl = ""}) {
_firestore
.collection("users")
.document(userId)
.updateData({"userName": userName, "photoUrl": photoUrl});
}
}
CollectionReference in cloud_firestore for flutter/dart does not have a document(..) method. It is called doc(..) instead. https://pub.dev/documentation/cloud_firestore/latest/cloud_firestore/CollectionReference/doc.html

Resources