如何使用 StreamBuilder 从 Firebase 检索嵌套数据并将其全部显示到 ListView
How to retrieve nested data from Firebase using StreamBuilder and display it all to ListView
我正在尝试从 Firebase 检索嵌套数组数据并将其显示在 ListView Builder 上,但我在下面遇到了错误。
Exception has occurred.
StateError (Bad state: field does not exist within the DocumentSnapshotPlatform)
请指导我。我需要帮助。
我用来将嵌套数据存储到主集合的模型
class SPMModel {
String? subjectName;
String? subjectGrade;
SPMModel(this.subjectName, this.subjectGrade);
Map<String, dynamic> toMap() => {
"subjectName": subjectName,
"subjectGrade": subjectGrade,
};
}
主要藏品的型号
class UserProfileModel {
String? uid;
String? email;
String? fullName;
String? nric;
String? age;
String? gender;
String? ethnicity;
String? religion;
String? address;
String? state;
String? country;
String? phone;
String? parentName;
String? parentPhone;
List<dynamic>? spmResult = []; //I'm using this variable to store the SPMModel data
UserProfileModel({
this.uid,
this.email,
this.fullName,
this.nric,
this.age,
this.gender,
this.ethnicity,
this.religion,
this.address,
this.state,
this.country,
this.phone,
this.parentName,
this.parentPhone,
this.spmResult
});
//receive data from database
factory UserProfileModel.fromMap(map) {
return UserProfileModel(
uid: map['uid'],
email: map['email'],
fullName: map['fullName'],
nric: map['nric'],
age: map['age'],
gender: map['gender'],
ethnicity: map['ethnicity'],
religion: map['religion'],
address: map['address'],
state: map['state'],
country: map['country'],
phone: map['phone'],
parentName: map['parentName'],
parentPhone: map['parentPhone'],
spmResult: map['spmResult']
);
}
//send data to database
Map<String, dynamic> toMap() {
return {
'uid': uid,
'email': email,
'fullName': fullName,
'nric': nric,
'age': age,
'gender': gender,
'ethnicity': ethnicity,
'religion': religion,
'address': address,
'state': state,
'country': country,
'phone': phone,
'parentName': parentName,
'parentPhone': parentPhone,
'spmResult': spmResult
};
}
}
我的 StreamBuilder
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection("users").where('uid', isEqualTo: FirebaseAuth.instance.currentUser!.uid).snapshots(),
builder: (context, snapshot){
if(!snapshot.hasData){
return const Center(child: Text('No data found'),);
}
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index){
return Column(
children: <Widget>[
Text('id : ${snapshot.data!.docs[index].toString()}'),
Text('subject: ${snapshot.data!.docs[index]['subjectName']}'),
Text('grade: ${snapshot.data!.docs[index]['subjectGrade']}'),
],
);
}
);
}
)
这是 Firebase 数据的样子
我自己的问题已经解决了
这是解决方案
StreamBuilder(
stream: FirebaseFirestore.instance.collection("users").doc(user!.uid).
snapshots(),
builder: (context, AsyncSnapshot snapshot){
if(!snapshot.hasData){
return const Text('No data found, yet');
}
return SingleChildScrollView(
child: DataTable(
border: TableBorder.all(),
columnSpacing: 0,
horizontalMargin: 8,
columns: <DataColumn>[
DataColumn(
label: SizedBox(
child: const Text('Subjects', textAlign: TextAlign.center),
width: MediaQuery.of(context).size.width * .60
)
),
DataColumn(
label: SizedBox(
child: const Text('Grades', textAlign: TextAlign.center),
width: MediaQuery.of(context).size.width * .15
)
),
DataColumn(
label: SizedBox(
child: const Text('Actions', textAlign: TextAlign.center),
width: MediaQuery.of(context).size.width * .15
)
),
],
rows: _buildList(context, snapshot.data['spmResult'])
),
);
},
)
我得到快照后,通过创建这些方法使用DataTable来显示数组
List<DataRow> _buildList(BuildContext context, List<dynamic> snapshot) {
return snapshot.map((data) => _buildListItem(context, data)).toList();
}
DataRow _buildListItem(BuildContext context, data) {
final record = SPMModel.fromJson(data);
return DataRow(
cells: <DataCell>[
DataCell(Text(record.subjectName.toString())),
DataCell(Center(child: Text(record.subjectGrade.toString()))),
const DataCell(Center(child: Icon(Icons.delete)))
]
);
}
对于我的模型,这是更新版本
用户Collection型号
class UserProfileModel {
List<SPMModel>? spmResult;
UserProfileModel({
this.spmResult,
});
//receive data from database
factory UserProfileModel.fromMap(map) {
return UserProfileModel(
spmResult: SPMModel.fromJsonArray(map['spmResult'])
);
}
//send data to database
Map<String, dynamic> toMap() {
return {
'spmResult': spmResult
};
}
}
数组模型
class SPMModel {
String? subjectName;
String? subjectGrade;
SPMModel({this.subjectName, this.subjectGrade});
Map<String, dynamic> toMap() => {
"subjectName": subjectName,
"subjectGrade": subjectGrade,
};
factory SPMModel.fromJson(Map<String, dynamic> json){
return SPMModel(
subjectName: json['subjectName'],
subjectGrade: json['subjectGrade']
);
}
static List<SPMModel> fromJsonArray(List<dynamic> jsonArray){
List<SPMModel> spmModelFromJson = [];
for (var item in jsonArray) {
spmModelFromJson.add(SPMModel.fromJson(item));
}
return spmModelFromJson;
}
}
用于存储数组到主collection
await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser!.uid)
.update({
"spmResult": FieldValue.arrayUnion([SPMModel(subjectName: subject, subjectGrad
grade).toMap()])
}).then((value) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text
('Successfully Added')));
})
.catchError((onError){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('${onError.
message}')));
});
我正在尝试从 Firebase 检索嵌套数组数据并将其显示在 ListView Builder 上,但我在下面遇到了错误。
Exception has occurred.
StateError (Bad state: field does not exist within the DocumentSnapshotPlatform)
请指导我。我需要帮助。
我用来将嵌套数据存储到主集合的模型
class SPMModel {
String? subjectName;
String? subjectGrade;
SPMModel(this.subjectName, this.subjectGrade);
Map<String, dynamic> toMap() => {
"subjectName": subjectName,
"subjectGrade": subjectGrade,
};
}
主要藏品的型号
class UserProfileModel {
String? uid;
String? email;
String? fullName;
String? nric;
String? age;
String? gender;
String? ethnicity;
String? religion;
String? address;
String? state;
String? country;
String? phone;
String? parentName;
String? parentPhone;
List<dynamic>? spmResult = []; //I'm using this variable to store the SPMModel data
UserProfileModel({
this.uid,
this.email,
this.fullName,
this.nric,
this.age,
this.gender,
this.ethnicity,
this.religion,
this.address,
this.state,
this.country,
this.phone,
this.parentName,
this.parentPhone,
this.spmResult
});
//receive data from database
factory UserProfileModel.fromMap(map) {
return UserProfileModel(
uid: map['uid'],
email: map['email'],
fullName: map['fullName'],
nric: map['nric'],
age: map['age'],
gender: map['gender'],
ethnicity: map['ethnicity'],
religion: map['religion'],
address: map['address'],
state: map['state'],
country: map['country'],
phone: map['phone'],
parentName: map['parentName'],
parentPhone: map['parentPhone'],
spmResult: map['spmResult']
);
}
//send data to database
Map<String, dynamic> toMap() {
return {
'uid': uid,
'email': email,
'fullName': fullName,
'nric': nric,
'age': age,
'gender': gender,
'ethnicity': ethnicity,
'religion': religion,
'address': address,
'state': state,
'country': country,
'phone': phone,
'parentName': parentName,
'parentPhone': parentPhone,
'spmResult': spmResult
};
}
}
我的 StreamBuilder
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection("users").where('uid', isEqualTo: FirebaseAuth.instance.currentUser!.uid).snapshots(),
builder: (context, snapshot){
if(!snapshot.hasData){
return const Center(child: Text('No data found'),);
}
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index){
return Column(
children: <Widget>[
Text('id : ${snapshot.data!.docs[index].toString()}'),
Text('subject: ${snapshot.data!.docs[index]['subjectName']}'),
Text('grade: ${snapshot.data!.docs[index]['subjectGrade']}'),
],
);
}
);
}
)
这是 Firebase 数据的样子
我自己的问题已经解决了
这是解决方案
StreamBuilder(
stream: FirebaseFirestore.instance.collection("users").doc(user!.uid).
snapshots(),
builder: (context, AsyncSnapshot snapshot){
if(!snapshot.hasData){
return const Text('No data found, yet');
}
return SingleChildScrollView(
child: DataTable(
border: TableBorder.all(),
columnSpacing: 0,
horizontalMargin: 8,
columns: <DataColumn>[
DataColumn(
label: SizedBox(
child: const Text('Subjects', textAlign: TextAlign.center),
width: MediaQuery.of(context).size.width * .60
)
),
DataColumn(
label: SizedBox(
child: const Text('Grades', textAlign: TextAlign.center),
width: MediaQuery.of(context).size.width * .15
)
),
DataColumn(
label: SizedBox(
child: const Text('Actions', textAlign: TextAlign.center),
width: MediaQuery.of(context).size.width * .15
)
),
],
rows: _buildList(context, snapshot.data['spmResult'])
),
);
},
)
我得到快照后,通过创建这些方法使用DataTable来显示数组
List<DataRow> _buildList(BuildContext context, List<dynamic> snapshot) {
return snapshot.map((data) => _buildListItem(context, data)).toList();
}
DataRow _buildListItem(BuildContext context, data) {
final record = SPMModel.fromJson(data);
return DataRow(
cells: <DataCell>[
DataCell(Text(record.subjectName.toString())),
DataCell(Center(child: Text(record.subjectGrade.toString()))),
const DataCell(Center(child: Icon(Icons.delete)))
]
);
}
对于我的模型,这是更新版本
用户Collection型号
class UserProfileModel {
List<SPMModel>? spmResult;
UserProfileModel({
this.spmResult,
});
//receive data from database
factory UserProfileModel.fromMap(map) {
return UserProfileModel(
spmResult: SPMModel.fromJsonArray(map['spmResult'])
);
}
//send data to database
Map<String, dynamic> toMap() {
return {
'spmResult': spmResult
};
}
}
数组模型
class SPMModel {
String? subjectName;
String? subjectGrade;
SPMModel({this.subjectName, this.subjectGrade});
Map<String, dynamic> toMap() => {
"subjectName": subjectName,
"subjectGrade": subjectGrade,
};
factory SPMModel.fromJson(Map<String, dynamic> json){
return SPMModel(
subjectName: json['subjectName'],
subjectGrade: json['subjectGrade']
);
}
static List<SPMModel> fromJsonArray(List<dynamic> jsonArray){
List<SPMModel> spmModelFromJson = [];
for (var item in jsonArray) {
spmModelFromJson.add(SPMModel.fromJson(item));
}
return spmModelFromJson;
}
}
用于存储数组到主collection
await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser!.uid)
.update({
"spmResult": FieldValue.arrayUnion([SPMModel(subjectName: subject, subjectGrad
grade).toMap()])
}).then((value) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text
('Successfully Added')));
})
.catchError((onError){
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('${onError.
message}')));
});