- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我努力达到的结果
我将 Firestore 服务器用作餐厅订单系统的 Flutter 应用程序的后端。在实现显示数据库实时更改的屏幕时,我发现自己遇到了一些挑战。
所以我有一个名为“表格”的集合,其中包含多个文档(不同的餐厅可能有不同的名称)。这些文档中的每一个都有几个字段,例如'登记时间'。此外,每个表文档还有一个订单集合(“子集合”)。
我想要一个Stream
在我的 Flutter 屏幕上,它接收所有表格,包括他们的订单。屏幕应该给出所有表格的概览,这意味着它应该在任何时候更新...
我有一个模型 Order
和 Table
类(class)。 Table 类的一个实例应该有一个 List<Order> _orders
其中包含存储在子集合中的所有订单。 Stream
应该给我提供 List<Table>
.
注意:我尝试使用 Flutter Web 来实现这一点,但这可能不会对我的问题的解决产生影响。
当前进度
到目前为止,我实际上几乎成功地解决了这个挑战。我设法得到一个 Stream
将所有表格显示在屏幕上。
在大多数情况下,它最初会成功加载数据。有时屏幕的第一次加载会导致无限加载 CircularProgressIndicator 而数据未加载。
当另一个表被添加到集合中时,屏幕会更新。添加订单不会立即起作用,但如果我第二次重新加载页面或在我将另一个订单添加到订单子(monad)集合后它会起作用。似乎错误的发生与时间无关。
似乎更新订单文档根本不起作用/重新加载订单状态。
在任何情况下都不会出现错误信息。
当前代码
类 TableInfo
对于流:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart' as m;
import '../../../../../domain/infrastructure/firestore_infrastructure.dart';
import '../../../../../domain/models/orders_models/order.dart';
import '../../../../../domain/models/orders_models/table.dart';
import '../../../../../locator.dart';
///Class for getting all tables and orders in realtime and managing the current filter settings.
class TableInfo extends m.ChangeNotifier {
///List of all tables
List<Table> _tables = [];
///List of all orders
List<Order> _orders = [];
final CollectionReference _tableCollection = locator<CustomFirestore>().tablesRef;
Stream<QuerySnapshot> get _stream => _tableCollection.snapshots();
///returns all tables in the Firestore `tables` collection of the restaurant.
///Also sets a listener for the orders and matches them from the [_orders] list.
Stream<List<Table>> getTableStream(
{void Function(Order savedOrder) onOrderSaved}) async* {
print("Reloading");
final tableDocs = await _tableCollection.get().then((value) => value.docs);
for (QueryDocumentSnapshot tableDoc in tableDocs) {
_tableCollection
.doc(tableDoc.id)
.collection(CustomFirestore.ORDERS_COLLECTION)
.snapshots()
.listen((snapshot) =>
_saveOrders(snapshot, tableDoc.id, onOrderSaved: onOrderSaved));
}
final tableStream =
_stream.map((snapShot) => _unfilteredTablesFromTableSnapshot(snapShot));
yield* tableStream;
}
///Help function to get all tables with ordes from a table doc snapshot.
List<Table> _unfilteredTablesFromTableSnapshot(QuerySnapshot snapShot) {
return snapShot.docs.map((tableDocument) {
final table = Table.fromSnapshot(tableDocument);
table.addOrders(_orders.where((element) => element.tableId == table.id),
overwrite: true);
_tables.add(table);
return table;
}).toList();
}
///Function to save the orders from a snapshot of an order collection of a single table.
void _saveOrders(QuerySnapshot orderCollectionSnapshot, String tableId,
{void Function(Order savedOrder) onOrderSaved}) {
final orderDocs = orderCollectionSnapshot.docs;
print(
"Saving ${orderDocs.length} orders for $tableId at ${DateTime.now()} :)");
for (QueryDocumentSnapshot orderDoc in orderDocs) {
final order = Order.fromSnapshot(orderDoc, tableId);
final existing = _orders.firstWhere(
(element) => element.orderId == order.orderId,
orElse: () => null);
if (existing != null) _orders.remove(existing);
_orders.add(order);
if (onOrderSaved != null) onOrderSaved(order);
}
}
}
如您所见,我首先获取所有表文档,然后为子集合“订单”添加一个监听器,称为 _saveOrders
.看起来代码首先获得订单,这就是我在 Table.fromSnapshot
中初始化表的原因使用 _orders = [] 然后从 _unfilteredTablesFromTableSnapshot
内的订单列表中添加订单方法。
这里是屏幕的相关部分build
方法(显然放在脚手架中):
final tableInfo = Provider.of<TableInfo>(context);
return StreamProvider.value(
value: tableInfo.getTableStream(),
catchError: (ctx, error) {
print("Error occured! $error");
print(error.runtimeType);
//throw error;
return [
t.Table(
id: 'fehler',
name: 'Fehler $error',
status: t.TableStatus.Free,
orders: [],
checkinTime: DateTime.now())
];
},
builder: (context, child) {
final allUnfilteredTables = Provider.of<
List<t.Table>>(
context); //corresponds to TableInfo.filteredTableStream
///while the Tables are loading:
if (allUnfilteredTables == null)
return Center(
child: CircularProgressIndicator());
///if there are no tables at all:
if (allUnfilteredTables.isEmpty)
return Text(
"No tables detected.");
///if an error occured:
if (allUnfilteredTables[0].id == 'fehler')
return Text(allUnfilteredTables[0].name);
return GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisSpacing: (50 / 1920) *
constraints.maxWidth,
crossAxisCount: isTablet ? 3 : 6),
itemCount: allUnfilteredTables.length,
itemBuilder: (ctx, index) {
t.Table table = allUnfilteredTables[index];
return TableMiniDisplay(table);
},
);
});
我已经尝试过的
我已经阅读了很多有关相关问题的文章,但找不到任何对我有很大帮助的答案来解决我剩下的错误。我也尝试使用 rxdart并使用 CombinedStream 但无法运行它。
实时同步的主要部分是有效的,所以我想只有很少的东西能阻止我成功,我感谢大家花时间阅读我的问题。我很感激任何可以帮助我的想法或代码示例。
(此外,如果您有任何其他改进代码的建议,请随时发表评论:))
提前致谢!
干杯,大卫
最佳答案
我建议您使用两个 Streambuilder 包装您的小部件。只需使用第一个来流式传输表,使用第二个来访问每个表中的订单。不要在每次要访问数据时都添加 Streambuilder。仅使用两个流生成数据并通过变量传递。
这是示例代码:
database.dart
import 'package:cloud_firestore/cloud_firestore.dart';
class Tables {
CollectionReference tablesReference =
FirebaseFirestore.instance.collection("tables");
Stream<QuerySnapshot> getTables() {
// Returns all tables
return tablesReference.snapshots();
}
Stream<QuerySnapshot> getOrdersFromTables(String tableName) {
// Returns specific table orders
return tablesReference.doc(tableName).collection("orders").snapshots();
}
}
main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'tables.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(),
// Initialize FlutterFire:
home: FutureBuilder(
future: Firebase.initializeApp(),
builder: (context, snapshot) {
// Check for errors
if (snapshot.hasError) {
return Center(
child: Text("Error"),
);
}
// Once complete, show your application
if (snapshot.connectionState == ConnectionState.done) {
return TablesPage();
}
// Otherwise, show something whilst waiting for initialization to complete
return Center(
child: CircularProgressIndicator(),
);
}),
);
}
}
表格.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'orders.dart';
import 'database.dart';
class TablesPage extends StatefulWidget {
@override
_TablesPageState createState() => _TablesPageState();
}
class _TablesPageState extends State<TablesPage> {
@override
Widget build(BuildContext context) {
// Get Tables
return Scaffold(
appBar: AppBar(
title: Text("Tables"),
),
body: StreamBuilder<QuerySnapshot>(
stream: Tables().getTables(),
builder: (context, tables) {
if (tables.hasError)
return Text(tables.error);
else if (tables.hasData) {
if (tables.data.docs.isEmpty) {
return Text("No tables.");
} else {
return ListView.builder(
itemCount: tables.data.docs.length,
itemBuilder: (context, index) {
// Get Orders
return StreamBuilder<QuerySnapshot>(
stream: Tables()
.getOrdersFromTables(tables.data.docs[index].id),
builder: (context, orders) {
if (orders.hasData) {
return ListTile(
title:
Text("Table ${tables.data.docs[index].id}"),
subtitle: Text(DateFormat("HH:mm").format(tables
.data.docs[index]["checkinTime"]
.toDate())),
trailing: Text(
"Total orders: ${orders.data.docs.length.toString()}"),
onTap: () {
// Navigate to Orders Page
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Orders(
orders: orders.data.docs,
),
),
);
});
} else {
return Container();
}
});
},
);
}
} else {
print(tables
.connectionState); //is stuck in ConnectionState.waiting or ConnectionState.active
return Center(child: CircularProgressIndicator());
}
},
),
);
}
}
订单.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class Orders extends StatelessWidget {
const Orders({
Key key,
@required this.orders,
}) : super(key: key);
final List<QueryDocumentSnapshot> orders;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Orders"),
),
body: ListView.builder(
itemCount: orders.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(orders[index].id),
subtitle: Text(orders[index]["barStatus"]),
leading: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text((index+1).toString()),
],
),
);
},
),
);
}
}
关于firebase - 在 Flutter 中收听 Firestore 集合及其子集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65044932/
我正在尝试为我的 Firestore 设置一个数据库,但是我尝试重新安装 pod 和许多其他东西,但我仍然无法让它工作,因为它显示了这个错误: Type 'Firestore' has no memb
我需要更改我的项目 ID,因为要验证的 Firebase 身份验证链接在链接上显示了项目 ID,并且由于品牌 reshape ,项目名称已更改。根据我发现的信息,更改项目 ID 似乎不太可能。我正在考
快速提问。长话短说,我在我的谷歌云功能日志中收到此错误: Firestore (4.10.1):无法到达 Firestore 后端。 这是我的函数文件中的代码: // pull in firebas
我正在从事 Angular 6 项目。这是我使用 --prod 构建时遇到的错误标记、主持和运行。我已经坐了很长时间了。最初认为这可能是 firestore 包的问题,我等了。但是现在更新到fir
我正在开发一个 React 项目,这是我的第一个 React 项目。此代码部署成功。但在使用 postman 测试时出现一些错误。我“发布”“createScream”函数的 URL 并发送它。然后我
我有一个包含两个集合的 Firestore 数据库:用户和锦标赛。用户具有“参与者”角色和“管理员”角色,并在用户文档中由“isParticipant”和“isAdmin” bool 值指示: /us
Firebase 数据库根据他们的文档提供了 10 MB 的离线数据库缓存限制,但没有提到 的离线数据限制。 Firestore 数据库。 Firestore 的离线数据保存限制是多少? 最佳答案 根
我正在尝试评估 string在 Firestore 安全规则 基于 matches正则表达式功能 我的代码是 username.matches('^(?!\.)(?!_)(?!.*\.$)(?!.*?
是否可以在 Firestore 中定义具有唯一约束的索引?如果没有,如何在文档字段上强制执行唯一性(不使用文档 ID)? 最佳答案 是的,这可以通过结合使用两个集合、Firestore 规则和批量写入
我正在学习 GCP,在他们的 Firestore 中,我对 Admin.firestore 和 Firebase.firestore 的区别感到困惑。 这是管理员的代码: const admin =
使用带有自定义声明的 firestore 在线安全模拟会导致错误,但它在部署时可以完美运行(同时实际处理真实请求)。错误是: Error: simulator.rules line [5], colu
所以,我知道有一些类似命名的问题,但这是不一样的。 我很想知道是否有人可以解释缺少 increment 的原因。哨兵,类似于delete一。 据我所知,字段删除与文档更新没有什么不同。意思是,我只能
我想创建两个带有分页选项的查询。在第一个记录中,我想获取前十条记录,在第二个记录中,我想获取其他所有记录: .startAt(0) .limit(10) .startAt(9) .limit(null
我正在努力为我的应用寻找最佳架构。我应该使用顶级集合、子集合、数组等吗? 设置: 我的应用程序将有许多用户将参与的测验。 每个测验都会有多个问题。 每个问题都有多个答案,只能选择一个。 每个用户只能回
我正在努力为我的应用寻找最佳架构。我应该使用顶级集合、子集合、数组等吗? 设置: 我的应用程序将有许多用户将参与的测验。 每个测验都会有多个问题。 每个问题都有多个答案,只能选择一个。 每个用户只能回
我无法在任何地方找到我可以在一个Collection中获得的文档数量的限制。假设我有1,000,000,000个文档...那有可能吗?如果我想把它们全部都拿走,实际上会给我十亿吗? 最佳答案 可以存储
假设我有一个集合 mycollection有 1,000,000 条记录。 此查询将返回多少条记录? const query = firestore.collection('mycollection'
这是错误消息:@firebase/firestore: Firestore (4.12.1): Could not reach Firestore backend 我正在构建一个网络应用程序,它今天运
我在编写和测试我的 Firestore 规则时遇到了一个奇怪的问题。这是我想要实现的目标: 当应用程序启动时,用户会匿名登录。这用户开始新游戏。 我创建了一个基本上只包含时间戳的“ session ”
我是云函数的新手。我有一些困惑。 admin.firestore 和functions.firestore? admin.database 是实时数据库吗? 因此,如果云函数基本上是用 JavaScr
我是一名优秀的程序员,十分优秀!