Firestore replicating a SQL Join for noSQL and Flutter
我意识到在复制NoSql文档数据库(例如FireStore)的联接方面存在很多问题,但是我无法找到将Dart / Flutter与FireStore结合使用的全面解决方案。
我进行了一些研究,我认为在以下示例中,我将寻找"多对多"关系(如果这是错的,请纠正我),因为将来可能需要查看所有个人资料以及所有连接。
在firebase中,我有两个根级别集合(配置文件
很遗憾,Cloud Firestore和其他NoSQL数据库中没有
因此,我能想到的最简单的解决方案是查询数据库以从
1 | stream: Firestore.instance.collection('connection').where('uid', isEqualTo:"xyc4567").snapshots(), |
另一种解决方案是在每个用户下创建一个名为
此外,在复制数据时,需要记住一件事。用与添加数据相同的方式,您需要对其进行维护。换句话说,如果要更新/删除项目,则需要在它存在的每个位置进行。
我做了这样的事情,将两个集合对象和类别的结果连接起来。
我做了两个StreamBuilder来显示在一个列表中,在第一个中,我获得了类别并放入了地图,然后我查询了对象并使用categoryID从地图中获得了类别对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | StreamBuilder<QuerySnapshot>( stream: Firestore.instance .collection('categoryPath') .snapshots(), builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> categorySnapshot) { //get data from categories if (!categorySnapshot.hasData) { return const Text('Loading...'); } //put all categories in a map Map<String, Category> categories = Map(); categorySnapshot.data.documents.forEach((c) { categories[c.documentID] = Category.fromJson(c.documentID, c.data); }); //then from objects return StreamBuilder<QuerySnapshot>( stream: Firestore.instance .collection('objectsPath') .where('day', isGreaterThanOrEqualTo: _initialDate) .where('day', isLessThanOrEqualTo: _finalDate) .snapshots(), builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> objectsSnapshot) { if (!objectsSnapshot.hasData) return const Text('Loading...'); final int count = objectsSnapshot.data.documents.length; return Expanded( child: Container( child: Card( elevation: 3, child: ListView.builder( padding: EdgeInsets.only(top: 0), itemCount: count, itemBuilder: (_, int index) { final DocumentSnapshot document = objectsSnapshot.data.documents[index]; Object object = Object.fromJson( document.documentID, document.data); return Column( children: <Widget>[ Card( margin: EdgeInsets.only( left: 0, right: 0, bottom: 1), shape: RoundedRectangleBorder( borderRadius: BorderRadius.all( Radius.circular(0)), ), elevation: 1, child: ListTile( onTap: () {}, title: Text(object.description, style: TextStyle(fontSize: 20)), //here is the magic, i get the category name using the map of the categories and the category id from the object subtitle: Text( categories[object.categoryId] != null ? categories[ object.categoryId] .name : 'Uncategorized', style: TextStyle( color: Theme.of(context) .primaryColor), ), ), ), ], ); }), ), ), ); |
我不确定您想要的是什么还是明确的,但希望对您有所帮助。
假设您要使用依赖于某些
1 2 3 4 5 6 7 8 9 10 | Stories Document ID (Auto Generated) //Suppose,"zddgaXmdadfHs" > name ="The Lion & the Warthog" > coverImage ="https://...." > author ="Furqan Uddin Fahad" > publisDate = 123836249234 Favorites Document ID (Auto Generated) > storyDocID ="zddgaXmdadfHs" //Document ID of a story > userId ="adZXkdfnhoa" //Document ID of a user |
SQL等效查询应如下所示
1 2 3 | SELECT * FROM Favorites AS f, Stories AS s WHERE f.storyDocID = s.DocumentID AND f.userId = user.userId |
这样的Firestore查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | final _storeInstance = Firestore.instance; Stream <List<Favorite>> getFavorites() async* { final user = await _getUser(); //_getUser() Returns Future<User> yield* _storeInstance .collection('Favorites') .where('userId', isEqualTo: user.userId) .snapshots() .asyncMap((snapshot) async { final list = snapshot.documents.map((doc) async { final story = await _getStory(doc['storyDocID']); return Favorite.from(doc, story); //Favorite.from(DocumentSnapshot doc, Story story) returns an instance of Favorite }).toList(); //List<Future<Favorite>> return await Future.wait(list); //Converts List<Future<Favorite>> to Future<List<Favorite>> }); } Future<Story> _getStory(String storyDocID) async { final docRef = _storeInstance .collection('Stories') .document(storyDocID); final document = await docRef.get(); final story = Story.from(document); return story; } |
我认为不应该使用宗派主义,因为要保持这种称谓,就必须对Firestore进行额外的写操作
相反,jorge vieira是正确的,因为与写操作相比,您可以进行两次读操作
因此最好读取两次而不是两次写入数据,并且记住大型项目中每一个士气低落的事物也是非常不切实际的。