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);
});
}
Related
I have this 2 model class this is my code
import 'package:json_annotation/json_annotation.dart';
part 'friends_model.g.dart';
#JsonSerializable()
class FriendsModel {
String name;
String title;
String? desc;
FriendsModel(
{required this.name,
required this.title,
this.desc});
Map<String, dynamic> toJson() => _$FriendsModelToJson(this);
factory FriendsModel.fromJson(Map<String, dynamic> map) =>
_$FriendsModelFromJson(map);
}
and then
import 'package:json_annotation/json_annotation.dart';
part 'dpct_model.g.dart';
#JsonSerializable()
class DpctModel {
String fullName;
List<FriendsModel> myFriends;
DpctModel(
{required this.fullName,
List<FriendsModel>? friendsList,
}): friendsList = friendsList ?? <FriendsModel>[],
Map<String, dynamic> toJson() => _$DpctModelToJson(this);
factory DpctModel.fromJson(Map<String, dynamic> map) =>
_$DpctModelFromJson(map);
}
Now I want to save this into Cloud Firestore Database
so the data will look like this
[![enter image description here][1]][1]
How / What is the proper way to save this into it ?
this is part of my code
final CollectionReference<DpctModel> _dpctCollectionReference =
CloudFirestoreService.myFirestore
.collection('dpct')
.withConverter<DpctModel>(
fromFirestore: (snapshot, _) =>
DpctModel.fromJson(snapshot.data()!),
toFirestore: (model, _) => model.toJson(),
);
I use this
Future create(DpctModel model) async {
for (var element in model.friendsList) {
Map<String, dynamic> value = element.toJson();
_dpctCollectionReference
.doc(model.nrp)
.collection('friends')
.add(value);
}
}
it add a record into Firestore but how to add together other non collection field ?
Because i try
await _dpctCollectionReference.doc(model.nrp).set(model);
but it return me an error
also the add collection method keep adding the same record
any suggestion, would be appreciated ?
I am resolving this issue by myself, it because of Json nested class mapping at my model and i didn't set it explisit to json
so this code should work fine, and i only need to set #JsonSerializable(explicitToJson: true) at my DpctModel class
Future create(DpctModel model) async {
await _dpctCollectionReference.doc(model.nrp).set(model);
}
and at My Model class
#JsonSerializable(explicitToJson: true)
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.
basically im struggling to create a function in my database.dart where i can call this function to display a specfic field in a specific document.
Example, i want to use Database.readUserProfileData('Profile', 'surname') to display the string/alt to a widget.
static Future<QuerySnapshot> readUserProfileData({
required String docId,
required String field,
}) async {
var ref = _mainCollection.get().then((querySnapshot) {
querySnapshot.docs.forEach((result) {
Object? data = result.data();
print(data);
});
});
}
Here is my database.dart
(please ignore the UpdateItem function as i have not configured it properly as i copied this from a template, or maybe update it for me lol sorry ;))
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
/* ------------------ Database Reference - Main Collection ------------------ */
final CollectionReference _mainCollection = _firestore.collection('_TestFB');
class Database {
static String? userUid;
/* -------------------------- Create User Database -------------------------- */
static Future<void> createUserDataFile({
required String uid,
required String surname,
required int mobile,
}) async {
DocumentReference documentReferencer =
_mainCollection.doc('UserData').collection(uid).doc('Profile');
Map<String, dynamic> data = <String, dynamic>{
"surname": surname,
"mobile": mobile,
};
_mainCollection
.doc('UserData')
.collection(uid)
.limit(1)
.get()
.then((snapshot) async {
if (snapshot.size == 1) {
print("**User Profile Exists");
} else {
await documentReferencer
.set(data)
.whenComplete(() => print("**New Profile Created for - " + uid))
.catchError((e) => print(e));
}
});
}
/* ------------------------- Read User Profile Data ------------------------- */
static Future<QuerySnapshot> readUserProfileData({
required String docId,
required String field,
}) async {
var ref = _mainCollection.get().then((querySnapshot) {
querySnapshot.docs.forEach((result) {
Object? data = result.data();
print(data);
});
});
}
Thanks in Advance
If you already have the document id, then just do:
static Future<DocumentSnapshot> readUserProfileData({
required String docId,
required String field,
}) async {
var ref = _mainCollection.doc(docId).get().then((snapshot) {
print(snapshot);
print(snapshot.data()[field]);
});
}
You don't need to use forEach since you are only retrieving one document and get() will have a return type Future<DocumentSnapshot>
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;
}
}
I am trying to build a chat application using Flutter & Firebase I took below code from Github and used it on my project. On an earlier version of Flutter, it was working, on 2.0 it is showing the following error: The argument type 'StreamTransformer<dynamic, dynamic>' can't be assigned to the parameter type 'StreamTransformer<QuerySnapshot, List<Message>>'
The error is triggered by the following line:
.transform(Utils.transformer(User.fromJson));
Full code:
class FirebaseApi {
static Stream<List<User>> getUsers() => FirebaseFirestore.instance
.collection('users')
// .collection('ch ats')
.orderBy(UserField.timestamp, descending: true)
.snapshots()
.transform(Utils.transformer(User.fromJson));
static Future uploadMessage(String idUser, String message) async {
final refMessages =
FirebaseFirestore.instance.collection('chats/$idUser/messages');
final newMessage = Message(
// idUser: myId,
idUser: Globals.auth.currentUser!.uid,
// urlAvatar: myUrlAvatar,
urlAvatar: ChatPageState.photoUrl.toString(),
// username: myUsername,
username: ChatPageState.displayName.toString(),
message: message,
createdAt: DateTime.now(),
);
await refMessages.add(newMessage.toJson());
final refUsers = FirebaseFirestore.instance.collection('users');
await refUsers.doc(idUser).update({UserField.timestamp: DateTime.now()});
}
static Stream<List<Message>> getMessages(String idUser) {
return FirebaseFirestore.instance
.collection('chats/$idUser/messages')
.orderBy(MessageField.createdAt, descending: true)
.snapshots()
.transform(Utils.transformer(Message.fromJson));
}
}
class Utils {
static StreamTransformer transformer<T>(
T Function(Map<String, dynamic> json) fromJson) =>
StreamTransformer<QuerySnapshot, List<T>>.fromHandlers(
handleData: (QuerySnapshot data, EventSink<List<T>> sink) {
final snaps = data.docs.map((doc) => doc.data()).toList();
final users = snaps.map((json) => fromJson(json)).toList();
sink.add(users);
},
);
static DateTime toDateTime(Timestamp value) {
// if (value == null);
return value.toDate();
}
static dynamic fromDateTimeToJson(DateTime date) {
if (date == null) return null;
return date.toUtc();
}
}
Add QuerySnapshot<Map<String, dynamic>> as your return type. worked for me.
static StreamTransformer<QuerySnapshot<Map<String, dynamic>>, List<T>> transformer<T>(
T Function(Map<String, dynamic> json) fromJson) =>
StreamTransformer<QuerySnapshot<Map<String, dynamic>>, List<T>>.fromHandlers(
handleData: (QuerySnapshot<Map<String, dynamic>> data, EventSink<List<T>> sink) {
final snaps = data.docs.map((doc) => doc.data()).toList();
final users = snaps.map((json) => fromJson(json)).toList();
sink.add(users);
},
);
The problem here is that return type of transformer function is dynamic while . transform function requires specific return type. Solution is to add return type like following:
static StreamTransformer<QuerySnapshot, List<T>> transformer<T>(
T Function(Map<String, dynamic> json) fromJson) =>
StreamTransformer<QuerySnapshot, List<T>>.fromHandlers(
handleData: (QuerySnapshot data, EventSink<List<T>> sink) {
final snaps = data.docs.map((doc) => doc.data()).toList();
final users = snaps.map((json) => fromJson(json)).toList();
sink.add(users);
},
);
so for any one that experience this problem change your dependency version to this
firebase_core: ^0.5.0+1
cloud_firestore: ^0.14.1+3
it worked for me, its dependency issue