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,
});
}
Related
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
I am developing an app with Flutter and Firebase.
I want to store the _id with SharedPreferences permanently.
Therefore, i looked after it, but my code doesnt work at all. It always throws the error:
type 'Future' is not a subtype of type 'String'
Here is my code:
class Profile with ChangeNotifier {
String _id;
void setName(String name) {
const url =
'myurl';
http
.post(url, body: json.encode({'name': name, 'description': name}))
.then((response) {
_id = json.decode(response.body)['name'];
});
addID();
}
Future<void> updateName(String name, String id) async {
String url =
'myurl';
await http.patch(url,
body: json.encode({'name': 'Ein Titel', 'description': name}));
}
And here are my methods with the SharedPrefs:
String getID() {
return getIDOffline();
}
addID() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('id', _id);
}
getIDOffline() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//Return String
String stringValue = prefs.getString('id');
return stringValue;
}
You have use wrong method for return string so you have to change String getID() to Future<String> getID(). And you can use like this.
getValue()async{
String value = await getID();
}
When you use async always try to add also Future.
like :
Future<returnType> methodName() async { }
In your code try to change
String getID(){ } to Future<String>getID() async{ }
I've created a map yet am having difficulty accessing the variable 'contact' within a stateful widget. I'm not sure where else to declare final Contact contact; .
The Contact model file.
class Contact {
int rating;
String name;
String location;
int phoneNumber;
String instagram;
int birthday;
String notes;
Contact(this.name, this.phoneNumber, this.location, this.rating,
this.instagram, this.birthday, this.notes);
Map<String, dynamic> toJson() => {
'Name': name,
'PhoneNumber': phoneNumber,
'Location': location,
'Rating': rating,
'Instagram': instagram,
'Birthday': birthday,
'Notes': notes,
};
Where final Contact contact; is currently declared
class NewContact extends StatefulWidget {
NewContact({Key key, #required this.contact}) : super(key: key);
final Contact contact;
#override
NewContactState createState() => NewContactState();
}
class NewContactState<T extends NewContact> extends State<T> {
final db = FirebaseFirestore.instance; //...etc
Where the Map is being called
await db
.collection("userData")
.doc(uid)
.collection("Contacts")
.add(contact.toJson());
Error = Undefined name 'contact'.
Since contact is defined in the class that extends statful widget, NewContact, and you want to access it's corresponding state class NewContactState, you should call it like this widget.contact.toJson().
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)
I have object "Lawer" has List of objects "maker"
class Lawer{
final int x1;
final int x2;
final int x3;
final List<Maker>objects
Lawer({this.x1,this.x2,this.x3 ,this.objects});
Map<String, dynamic> toJson() =>
{
'x1':1 ,
'x2':1,
'x3':2,
};
}
class Maker{
final String lawerID;
final String customerID;
final bool connect;
Maker({this.lawerID,this.customerID,this.connect=false});
Map<String, dynamic> toJson() =>
{
'lawerID':lawerID,
'customerID':customerID,
'connect':connect,
};
}
CollectionReference dPReplies=FirebaseFirestore.instance.collection('lawers'); FirebaseFirestore.instance.runTransaction((Transaction tx)async {
var result=await dPReplies.add(lawer.toJson())
});
how to save this object in firebase"save object have some variables and list of objects"
Change this in your class:
Map<String, dynamic> toJson() =>
{
'x1':x1,
'x2':x2,
'x3':x3,
};
You need to capitalize Lawer
var result= await dPReplies.add(Lawer.toJson()) //instead of lawer.toJson