I'm using back4app.com services (Prase SDK) on my flutter project to handle my backend.
in this method I try to query on specific object :
Future<List> getList(String date) async {
final QueryBuilder<ParseObject> parseQuery =
QueryBuilder<ParseObject>(ParseObject('UsersEaten'));
parseQuery
..whereContains('eatenBy', getUsrName!)
..whereEqualTo('eatenDate', date);
final ParseResponse apiResponse = await parseQuery.query();
if (apiResponse.success && apiResponse.results != null) {
List<dynamic>? apiRes = apiResponse.results;
and I've got whole data about this object as a List of Map :
[{"className":"UsersEaten","objectId":"OmrLz358Cb","createdAt":"2021-09-12T11:27:41.824Z","updatedAt":"2021-09-12T11:27:41.824Z","eatenTitle":"egg roll","eatenCal":180,"eatenFat":40,"eatenProtein":30,"eatenCarb":10,"eatenBy":"usr45","eatenDate":"2021-09-12"}, {"className":"UsersEaten","objectId":"lWIeMw54mH","createdAt":"2021-09-12T12:37:21.389Z","updatedAt":"2021-09-12T12:37:21.389Z","eatenTitle":"meat butter","eatenCal":235,"eatenFat":34,"eatenProtein":34,"eatenCarb":9,"eatenBy":"usr45","eatenDate":"2021-09-12"}]
but I dont need whole data I just want a specific Key , Values from this map for example I just need UsersEaten key values, how should I apply this kind of filter in my query???
In case I understand your question right, you want to reduce the amount of keys returned by the server.
This can be achieved using keysToReturn(List<String> keys).
/// Define which keys in an object to return.
///
/// [String] keys will only return the columns of a result you want the data for,
/// this is useful for large objects
void keysToReturn(List<String> keys) {
limiters['keys'] = concatenateArray(keys);
}
So your query might look something like this:
parseQuery
..whereContains('eatenBy', getUsrName!)
..whereEqualTo('eatenDate', date)
keysToReturn(['YOUR_KEY_THAT_SHOULD_BE_RETURNED']);
There is also the exact opposite of this method available, called excludeKeys(List<String> keys).
Create data class I chose the name Example for it
class Example {
String? className;
String? objectId;
String? createdAt;
String? updatedAt;
String? eatenTitle;
int? eatenCal;
int? eatenFat;
int? eatenProtein;
int? eatenCarb;
String? eatenBy;
String? eatenDate;
Example({
this.className,
this.objectId,
this.createdAt,
this.updatedAt,
this.eatenTitle,
this.eatenCal,
this.eatenFat,
this.eatenProtein,
this.eatenCarb,
this.eatenBy,
this.eatenDate,
});
Map<String, dynamic> toMap() {
return {
'className': className,
'objectId': objectId,
'createdAt': createdAt,
'updatedAt': updatedAt,
'eatenTitle': eatenTitle,
'eatenCal': eatenCal,
'eatenFat': eatenFat,
'eatenProtein': eatenProtein,
'eatenCarb': eatenCarb,
'eatenBy': eatenBy,
'eatenDate': eatenDate,
};
}
factory Example.fromMap(Map<String, dynamic> map) {
return Example(
className: map['className'],
objectId: map['objectId'],
createdAt: map['createdAt'],
updatedAt: map['updatedAt'],
eatenTitle: map['eatenTitle'],
eatenCal: map['eatenCal'],
eatenFat: map['eatenFat'],
eatenProtein: map['eatenProtein'],
eatenCarb: map['eatenCarb'],
eatenBy: map['eatenBy'],
eatenDate: map['eatenDate'],
);
}
String toJson() => json.encode(toMap());
factory Example.fromJson(String source) => Example.fromMap(json.decode(source));
}
Unfortunately, I don't know how to use this service back4app.com, but it should look like this
if (apiResponse.success && apiResponse.results != null) {
final maps = jsonDecode(apiResponse.results).cast<Map<String, dynamic>>();
var exampleList = List.generate(maps.length, (i) {
return Example.fromMap(maps[i]);
});
//sum of calories
num sum = 0;
exampleList.forEach((element){sum += element.eatenCal;});
print(sum);
}
Related
Actually, I am trying to get data from firebase and I am suffering from the Error:
Expected a value of type List < Khana >, but got one of type 'List< dynamic >'
I am getting data from the firebase, my fetchData function is:
Future<void> fetchAndSetOrder() async {
try {
await collectionRef.get().then((querySnapshot) {
for (var result in querySnapshot.docs) {
debugPrint("${result.runtimeType}=> ${result.data()}");
Orders newOrder = Orders.fromFirestore(result);
debugPrint("\n new order : $newOrder");
// _Order.add(newOrder);
debugPrint("new order added");
// _Order.add(Orders.fromMap(result as Map));
}
});
} catch (e) {
debugPrint("Error during Fetch:- $e");
}
}
and the Orders.fromFirestore constructor is:
factory Orders.fromFirestore(DocumentSnapshot<Object?> snapshot) {
final data = snapshot.data() as LinkedHashMap<String, dynamic>;
debugPrint("Inside From Firestore Function");
return Orders(
khana: data['khana'], // here is the error...
orderNumber: data['orderNumber'],
userId: data['userId'],
paymentCash: data['paymentCash'],
dateTime: data['dateTime'],
);
}
Orders class has:
class Orders{
List<Khana> khana; // this is another ModelClass
String userId;
int orderNumber;
DateTime dateTime;
bool paymentCash;
Orders({
required this.khana,
required this.userId,
required this.orderNumber,
required this.dateTime,
required this.paymentCash,
});
}
so, the issue is how can I read List from the firestore as a List ? Any other possible way to solve this issue.
My Khana Model is:
import 'dart:convert';
class Khana {
String mealName;
int id;
int price;
int quantity;
Khana({
required this.mealName,
required this.price,
required this.quantity,
required this.id,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'mealName': mealName});
result.addAll({'id': id});
result.addAll({'price': price});
result.addAll({'quantity': quantity});
return result;
}
factory Khana.fromMap(Map<String, dynamic> map) {
return Khana(
mealName: map['mealName'] ?? '',
id: map['id']?.toInt() ?? 0,
price: map['price']?.toInt() ?? 0,
quantity: map['quantity']?.toInt() ?? 0,
);
}
String toJson() => json.encode(toMap());
factory Khana.fromJson(String source) => Khana.fromMap(json.decode(source));
}
I am trying to read a List from the firestore snapshot.data(), it says it's return data type is List, and I want this list to be assigned to the List of my own ModelClass (i.e Khana), and I am not able to do that.
I even tried
factory Orders.fromFirestore(DocumentSnapshot<Object?> snapshot) {
final data = snapshot.data() as LinkedHashMap<String, dynamic>;
debugPrint("Inside From Firestore Function");
return Orders(
khana: data['khana'] as List<Khana>,
orderNumber: data['orderNumber'],
userId: data['userId'],
paymentCash: data['paymentCash'],
dateTime: data['dateTime'],
);
}
but got the same issue :(
Change your khana to this
khana: List<Khana>.from(data['khana'].map((x)=>Khana.fromJson(x)));
I am saving an object in the objectbox. As you can see in the screenshot the attribute "status" is not null. But when I access the object, the attribute appears to be null (other screenshot). Where Is my mistake?
Entity:
import 'package:admin_app/data/dto/enums.dart';
import 'package:admin_app/data/dto/model.dart';
import 'package:objectbox/objectbox.dart';
#Entity()
class UnknownCachedTicketScanEntity implements TicketScanDTOIn{
int id = 0;
String? eventId;
String? ticketId;
String? action;
List<String>? eventIdList;
bool? offline;
String? verificationId;
int? timestamp;
String? statusAsString;
TicketStatus? status;
UnknownCachedTicketScanEntity({
this.eventId,
this.action,
this.eventIdList,
this.offline,
this.ticketId,
this.verificationId,
this.timestamp,
this.statusAsString,
this.status
});
UnknownCachedTicketScanEntity.fromDTO(TicketScanDTOIn? ticketScanDTOIn, String eventId) {
ticketId = ticketScanDTOIn?.ticketId;
verificationId = ticketScanDTOIn?.verificationId;
status = ticketScanDTOIn?.status;
this.eventId = eventId;
}
#override
Map<String, dynamic> toJson() => {};
}
implemented class:
#JsonSerializable()
class TicketScanDTOIn {
String? action;
List<String>? eventIdList;
String? ticketId;
String? verificationId;
bool? offline;
int? timestamp;
TicketStatus? status;
TicketScanDTOIn({
this.action,
this.eventIdList,
this.ticketId,
this.verificationId,
this.offline,
this.timestamp,
this.status,
});
factory TicketScanDTOIn.fromJson(Map<String, dynamic> json) =>
_$TicketScanDTOInFromJson(json);
Map<String, dynamic> toJson() => _$TicketScanDTOInToJson(this);
}
storing in objectbox:
final _cachedUnknownTicketsBox = service<ObjectBox>().store?.box<UnknownCachedTicketScanEntity>();
_cachedUnknownTicketsBox?.put(UnknownCachedTicketScanEntity.fromDTO(ticketScanDTOIn, eventId));
trying to access the status:
TicketStatus? checkStatus(ticketId) {
final _cachedUnknownTicketsBox =
service<ObjectBox>().store?.box<UnknownCachedTicketScanEntity>();
final ticket = _cachedUnknownTicketsBox
?.getAll()
.where((cachedTicket) => cachedTicket.ticketId == ticketId)
.toList();
if (ticket != null && ticket.isEmpty) return TicketStatus.TICKET_NOT_USED;
final ticketStatus = ticket?.last.status;
return ticketStatus;
}
status not null
status null
When running ObjectBox generator you should have received a warning that TicketStatus is not a supported type. You either have to create a custom mapping to a supported database type for it, or create a relation. As TicketStatus appears to be an enum, converting it should do.
To convert it and store it as an int, add a getter/setter e.g. like:
TicketStatus? status;
int? get dbStatus {
return status?.index;
}
set dbStatus(int? index) {
// TODO Map from index to your enum,
// make sure to handle null and
// invalid values.
}
Source with example: https://docs.objectbox.io/advanced/custom-types#convert-annotation-and-property-converter
I use complex objects to manage data in my app. For example I have an object defined by the "Defi class" (meaning Challenge in French).
Here is the Defi class :
class Defi {
final int modeApprentissage;
final DateTime date;
final double score;
final int seconds;
final List mots;
final List erreurs;
final List listes;
final int langue;
final int type;
final int typeMots1;
final int typeMots2;
const Defi(
{required this.modeApprentissage,
required this.date,
required this.type,
required this.langue,
required this.typeMots1,
required this.typeMots2,
required this.score,
required this.seconds,
required this.listes,
required this.mots,
required this.erreurs});
}
I have a LIST of Defi that I would like to save on FIREBASE FIRESTORE.
My question : Is it absolutely necessary to transform my list of Defi into a map to save it on Firestore ? Or is there another way ?
Here is how I do it :
List _defisMap = [];
for (Defi def in _defis) {
_defisMap.add({
'modeApprentissage': def.modeApprentissage,
'type': def.type,
'langue': def.langue,
'typeMots1': def.typeMots1,
'typeMots2': def.typeMots2,
'date': def.date,
'score': def.score,
'seconds': def.seconds,
'listes': def.listes,
'mots': def.mots,
'erreurs': def.erreurs,
});
}
if (await _connectivity.checkConnectivity() != ConnectivityResult.none) {
await FirebaseFirestore.instance
.collection('familyAccounts')
.doc(_accountEmail)
.update({
'defis': _defisMap,
});
I read in some article that in classes such as Defi, I could add a "factory" constructor ? Does this have anything to do with what I'd like to do ?
I created another class :
class Classes {
final String code;
final String nom;
const Classes({
required this.code,
required this.nom,
});
Map<String, dynamic> toJson() => {
'code': code,
'nom': nom,
};
factory Classes.fromMap(Map data) => Classes(
code: data['code'] ?? '',
nom: data['nom'] ?? '',
);
}
I save a list of Classes on Firestore. No problem.
But to retrieve this list : I must go from the list of maps that is on Firestore to a list of "Classes". And I just can't get the syntax right !
Here is my code :
final DocumentSnapshot<Map<String, dynamic>> docInfo =
await FirebaseFirestore.instance
.collection('familyAccounts')
.doc(_accountEmail)
.get();
_typeCompte =
docInfo['typeCompte'] == 'prof' ? TypeCompte.prof : TypeCompte.eleve;
_userId = docInfo['userId'];
_linked = docInfo['linked'];
_name = docInfo['name'];
_avatar = docInfo['avatar'];
_classe = docInfo['classe'];
_classeCode = docInfo['classeCode'];
_country = docInfo['country'];
_region = docInfo['region'];
docInfo['langue'] == 'french'
? _selectedIoLanguage = Language.french
: _selectedIoLanguage = Language.english;
_teacherCode = docInfo['teacherCode'];
_indexList = docInfo['indexList'];
_nbrList = docInfo['nbrList'];
_dateCreationCompte = docInfo['dateCreation'].toDate();
_defiTemp = docInfo['defis'].toList();
if (_typeCompte == TypeCompte.prof) {
_etablissement = docInfo['etablissement'];
_mesClasses = docInfo['mesClasses'];
(_mesClasses should be a list of "Classes").
I sense it should be some kind of xxx.map() etc.... but I don't master this syntax.
You need to create toJson method to set as a map of your list. If you have a list of Defi class. You can send it to map.
class Defi {
final int modeApprentissage;
final DateTime date;
final double score;
final int seconds;
final List mots;
final List erreurs;
final List listes;
final int langue;
final int type;
final int typeMots1;
final int typeMots2;
const Defi(
{required this.modeApprentissage,
required this.date,
required this.type,
required this.langue,
required this.typeMots1,
required this.typeMots2,
required this.score,
required this.seconds,
required this.listes,
required this.mots,
required this.erreurs});
Map<String, dynamic> toJson() => {
'modeApprentissage': modeApprentissage,
'type': type,
'langue': langue,
'typeMots1': typeMots1,
'typeMots2': typeMots2,
'date': date,
'score': score,
'seconds': seconds,
'listes': listes,
'mots': mots,
'erreurs': erreurs,
};
}
Your list name is should be List<Defi> _defis then map it with toJson. var jsonMap = _defisMap.map((e) => e.toJson()).toList();
var jsonMap = _defis.map((e) => e.toJson()).toList();
if (await _connectivity.checkConnectivity() != ConnectivityResult.none) {
await FirebaseFirestore.instance
.collection('familyAccounts')
.doc(_accountEmail)
.update({
'defis': jsonMap,
});
You can also Map it from api call with fromJson method. Here is the way. Add this to your Defi class.
factory Defi.fromJson(Map<String, dynamic> json) {
return Defi(
modeApprentissage: json['modeApprentissage'],
type: json['type'],
langue: json['langue'],
typeMots1: json['typeMots1'],
typeMots2: json['typeMots2'],
date: json['date'],
score: json['score'],
seconds: json['seconds'],
listes: json['listes'],
mots: json['mots'],
erreurs: json['erreurs'],);
}
And when you call api you need to call that function.
final Map<String, dynamic> jsonResult = json.decode(response.body);
//if it is a list returning from api. You can change variables what you got from api.
(jsonResult as List<dynamic>)
.map((data) => Defi.fromJson(data))
.toList();
// if it is not list
Defi.fromJson(jsonResult);
Yes, it's absolutely necessary to transform into a map. Firestore is a document store, the definition of a document is a json object, which is represented by a map in Dart. BUT, you don't have to do it "manually". Most of us use packages to do the mapping for us.
Freezed or JsonSerializable and then we simply call .toJson and pass that to the function. In addition to that Firestore now supports the .withConverter function so you don't have to do any conversion if you know what type the collection is storing.
So if you know the type of a collection is Defi you can do
final defyCollection = FirebaseFirestore.instance.collection('defis').withConverter<Defi>(
fromFirestore: (snapshot, _) {
final data = snapshot.data()!;
data['id'] = snapshot.id;
return Defi.fromJson(data);
},
toFirestore: (object, _) => object.toJson(),
)
This way you can simply use the defyCollection and the data property or function will be typed to your type.
I receive an object from my payload data (which has to be a String) like this: {id: 24VQUCeGD4KnW6tvfhj8MJjuASk, event: user}. Since it is a string now, how can I access the key and value pair of both items in flutter from a String? I have tried creating a model class for it, making a Map again out of the String, decoding it back to json object but all failed. How can I get the key/value pair in a proper way?
Code:
await _notificationsPlugin.show(
id,
'New notification',
'You have received a new notification!',
notificationDetails,
payload: message.data.toString(), // the payload data has to be a string
);
When you press on the notification:
onSelectNotification: (String data) async {
//here is where I want to access the key/value pair of that String 'data'
// i tried something like this but failed
var someData = jsonEncode(jsonDecode(data));
var className = ClassName.fromJson(someData);
print(className.id);
.. but nothing prints
//... some logic
}
class ClassName {
ClassName({
this.id,
this.event,
});
String id;
String event;
ClassName.fromJson(Map<String, dynamic> json) {
id = json['id'];
user = json['event'];
}
}
Any form of help is appreciated!
try this:
import 'dart:convert';
void processData(String data) {
Map<String, dynamic> someData = jsonDecode(data);
var className = ClassName.fromJson(someData);
print(className.id);
}
class ClassName {
ClassName({
required this.id,
required this.user,
});
String id;
String user;
ClassName.fromJson(Map<String, dynamic> json) :
id = json['id'],
user = json['user'];
}
void main() {
processData("{\"id\": \"24VQUCeGD4KnW6tvfhj8MJjuASk\", \"user\": \"user\"}");
}
p.s it seems that your provided JSON has id and event keys but in your ClassName, you are reading id and user keys which doesn't exist.
it happens that the id string isn't delimited so, you may try to custom decode like:
Map<String, String> decodePayload(String eventData) {
final aString = eventData.substring(5, eventData.length - 1);
final parts = aString.split(', ');
final id = parts[0];
final event = parts[1].substring(7, );
return {'id': id, 'event':event};
}
It doesn't looks nice but it may works
I have list of users. I need to sort this user data based on gender. gender = { 0: 'male', 1: 'female', 2: 'others'}.
I want the date to be ordered in such a way that females are listed first, followed by males and then others i.e, {1, 0, 2}.
class User {
String id;
String name;
int gender;
User({
this.id,
this.name,
this.gender,
})
factory users.fromMap(Map<String, dynamic> data, String documentId) {
if (data == null) {
return null;
}
return User(
...
);
}
Map<String, dynamic> toMap() => <String, dynamic>{
...
}
}
Is there anyway to sort the data based on the above condition and return a stream again?
The stream I receive from database is below:
Stream<List<User>> users =
database.usersStream();
Now, is users object sortable using rxdart or is there any other way?
and how to do that?
You can sort the list in your usersStream method.
Try the following steps.
1. Implement Comparable in your User class and override the compareTo method.
class User implements Comparable<User> {
String id;
String name;
int gender;
User({
this.id,
this.name,
this.gender,
});
#override
String toString() {
return "User(id: $id, gender: $gender)";
}
#override
int compareTo(User other) {
if (gender == 1) {
return -1;
}
if (other.gender == 1) {
return 1;
}
return gender.compareTo(other.gender);
}
}
2. Sort the list in usersStream using the compareTo method.
Stream<List<User>> usersStream() async* {
//This is dummy data for users.
List<User> users = List.generate(20, (index) {
Random random = Random();
int gender = random.nextInt(3);
return User(id: index.toString(), gender: gender, name: "User $index");
});
//Sorting the list.
users.sort((User a, User b) {
return a.compareTo(b);
});
yield users;
}