[英]Convert Firestore DocumentSnapshot to Map in Flutter
I need to update a document with nested arrays in Firestore with Flutter.我需要使用 Flutter 在 Firestore 中更新嵌套 arrays 的文档。
So I need to get the full document into a Map, reorder the maps in the "sections" array, and then store the data back into the document.所以我需要将完整的文档放入 Map,重新排序“sections”数组中的地图,然后将数据存储回文档中。
I'm however unfamiliar how I can get the data of the snapshot (DocumentSnapshot) into a Map.然而,我不熟悉如何将快照 (DocumentSnapshot) 的数据放入 Map。
Below an example that doesn't work of what I try to achieve:下面是一个对我试图实现的目标不起作用的例子:
final Map<String, dynamic> doc = snapshot.data as Map<String, dynamic>;
"snapshot.data" contains the values of the document. “snapshot.data”包含文档的值。 The structure of the document looks like this:
文档的结构如下所示:
{
name: "Course 1"
sections: [
{name: "Section 1"},
{name: "Section 2"}
]
}
Once the Maps in the sections array have been re-ordered, I need to save the data back into the document. sections 数组中的地图重新排序后,我需要将数据保存回文档中。
Here the full function. Relevant code is in "onDragFinish".这里是完整的function。相关代码在“onDragFinish”中。
// Build editable list with draggable list tiles and swipe to delete
List<Widget> buildListViewEdit() {
final course = db.collection("school").document("3kRHuyk20UggHwm4wrUI")
.collection("course").document("74UsE9x7Bsgnjz8zKozv").snapshots();
return [
StreamBuilder(
stream: course,
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text("Loading...");
return Expanded(
child: DragAndDropList(
snapshot.data["sections"].length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(snapshot.data["sections"][index]["name"]),
onTap: () {
print("hello");
}
)
);
},
onDragFinish: (before, after) {
print('on drag finish $before $after');
//final docString = snapshot.data.toString();
final Map <String, dynamic> doc = snapshot.data;
//final tempSections = List.castFrom(snapshot.data["sections"]).toList();
//Map data = tempSections[before];
//tempSections.removeAt(before);
//tempSections.insert(after,data);
//snapshot.data["sections"] = tempSections;
//db.collection("school").document("3kRHuyk20UggHwm4wrUI")
//.collection("course").document("74UsE9x7Bsgnjz8zKozv").updateData(snapshot.data);
//var line = snapshot.data["sections"][before];
//snapshot.data["sections"].removeAt(before);
//snapshot.data["sections"].insert(after,line);
/*
List<Map> sections = docCopy["sections"];
Map data = docCopy["sections"][before];
sections.removeAt(before);
sections.insert(after, data);
print(sections);
*/
},
canDrag: (index) {
print('can drag $index');
return index != 3;
},
canBeDraggedTo: (one, two) => true,
dragElevation: 8.0,
)
);
}
)
];
}
Error when trying to copy snapshot.data into another variable:尝试将 snapshot.data 复制到另一个变量时出错:
flutter: ══╡ EXCEPTION CAUGHT BY GESTURE LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following assertion was thrown while routing a pointer event:
flutter: type 'DocumentSnapshot' is not a subtype of type 'Map<String, dynamic>'
flutter:
flutter: Either the assertion indicates an error in the framework itself, or we should provide substantially
flutter: more information in this error message to help you determine and fix the underlying cause.
flutter: In either case, please report this assertion by filing a bug on GitHub:
flutter: https://github.com/flutter/flutter/issues/new?template=BUG.md
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0 _SectionScreenState.buildListViewEdit.<anonymous closure>.<anonymous closure> (package:teach_mob/screens/section_screen.dart:150:45)
Working example工作示例
Thanks all for your assistance.感谢大家的协助。 Here a full example that worked for me:
这是一个对我有用的完整示例:
// Build editable list with draggable list tiles and swipe to delete
List<Widget> buildListViewEdit() {
final course = db.collection("school").document("3kRHuyk20UggHwm4wrUI")
.collection("course").document("74UsE9x7Bsgnjz8zKozv").snapshots();
return [
StreamBuilder(
stream: course,
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text("Loading...");
return Expanded(
child: DragAndDropList(
snapshot.data["sections"].length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(snapshot.data["sections"][index]["name"]),
onTap: () {
print("hello");
}
)
);
},
onDragFinish: (before, after) {
print('on drag finish $before $after');
// Convert AsyncSnapshot to DocumentSnapshot and then
// create a map that can be changed and updated.
final Map <String, dynamic> doc = snapshot.data.data;
// Convert fixed length list to dynamic list, because items in
// fixed length lists can't be added / removed.
final tempSections = List.castFrom(doc["sections"]).toList();
// Get the data of the list item to be dragged
// Remove the data from the current position
// Add the data to the new position of the list
Map data = tempSections[before];
tempSections.removeAt(before);
tempSections.insert(after,data);
// Overwrite sections with new list array
doc["sections"] = tempSections;
// Store the data back into the firestore document
db.collection("school")
.document("3kRHuyk20UggHwm4wrUI")
.collection("course")
.document("74UsE9x7Bsgnjz8zKozv")
.updateData(doc);
},
canDrag: (index) {
print('can drag $index');
return index != 3;
},
canBeDraggedTo: (one, two) => true,
dragElevation: 8.0,
)
);
}
)
];
}
As per our discussion snapshot is not a DocumentSnapshot
it is AsyncSnapshot
根据我们的讨论,快照不是
DocumentSnapshot
,而是AsyncSnapshot
to get the DocumentSnaphot use snapshot.data
获取 DocumentSnaphot 使用
snapshot.data
to get the actual map you can use snapshot.data.data()
要获得实际地图,您可以使用
snapshot.data.data()
Which will return the Map<String, dynamic> you are looking for.这将返回您正在寻找的 Map<String, dynamic> 。
Needed to simplify for purpose of example出于示例目的需要简化
class ItemsList extends StatelessWidget {
@override
Widget build(BuildContext context) {
// get the course document using a stream
Stream<DocumentSnapshot> courseDocStream = Firestore.instance
.collection('Test')
.document('4b1Pzw9MEGVxtnAO8g4w')
.snapshots();
return StreamBuilder<DocumentSnapshot>(
stream: courseDocStream,
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
// get course document
var courseDocument = snapshot.data.data;
// get sections from the document
var sections = courseDocument['sections'];
// build list using names from sections
return ListView.builder(
itemCount: sections != null ? sections.length : 0,
itemBuilder: (_, int index) {
print(sections[index]['name']);
return ListTile(title: Text(sections[index]['name']));
},
);
} else {
return Container();
}
});
}
}
Looks like maybe because you got a stream builder, so the Snapshot is a AsyncSnapshot<dynamic>
, when you grab its .data, you get a dynamic , which returns a DocumentSnapshot , which then you need to call .data on this object to get the proper Map<String, dynamic> data
.看起来可能是因为你有一个流生成器,所以Snapshot是一个
AsyncSnapshot<dynamic>
,当你获取它的 .data 时,你得到一个dynamic ,它返回一个DocumentSnapshot ,然后你需要在这个对象上调用 .data来获取正确的Map<String, dynamic> data
。
builder: (context, snapshot) {
final DocumentSnapshot ds = snapshot.data;
final Map<String, dynamic> map = ds.data;
}
You can also append to arrays using in-built functions, but looks like you wanna do some crazy sorting so all good.你也可以使用内置函数附加到数组,但看起来你想做一些疯狂的排序,所以一切都很好。
Updated September-2020 2020 年 9 月更新
To get data from a snapshot document you now have to call snapshot.data()
(cloud_firestore 0.14.0 or higher
)要从快照文档中获取数据,您现在必须调用
snapshot.data()
(cloud_firestore 0.14.0 or higher
)
Update May 2021 2021 年 5 月更新
See Migration to cloud_firestore 2.0.0 here .请参阅此处的迁移到 cloud_firestore 2.0.0。
//Replace this:
- StreamBuilder<DocumentSnapshot>(
//With this:
+ StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
The type has to be defined when creating variables:创建变量时必须定义类型:
Future<void> example(
- DocumentReference documentReference,
+ DocumentReference<Map<String, dynamic>> documentReference,
- CollectionReference collectionReference,
+ CollectionReference<Map<String, dynamic>> collectionReference,
- Query query,
+ Query<Map<String, dynamic>> query,
) {
要从文档snapshot.data.data
获取地图,请使用snapshot.data.data
I think you are all wrong here.我觉得你们都错了。
The only way to get Map field from Firestore database is using this code docs.get("MapVariableName") as Map<String, dynamic>
, like in this example code below:从 Firestore 数据库获取 Map 字段的唯一方法是使用此代码
docs.get("MapVariableName") as Map<String, dynamic>
,如下面的示例代码所示:
Widget userFstore(BuildContext context, DocumentSnapshot docs, int index) { //Assign it into new Map using variable late Map late Map<String, dynamic> userInfo = docs["user"] as Map<String, dynamic>; //Then access its key like this method below late String name = userInfo["name"] as String; late String imgURL = userInfo["imgURL"] as String; late String imgName = userInfo["imgName"] as String; late String desc = userInfo["desc"] as String; late String email = userInfo["email"] as String; late bool active = userInfo["active"] as bool; return const SizedBox(); }
Building on above answers you can try something like基于以上答案,您可以尝试类似的方法
Position p = snapshot.data as Position;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.