How can I add 3 widgets in one? - firebase

I am trying to show 3 widgets with 3 different on tap functions, but it is not working.
So what I want is the whole widget split in 3 different widgets so I can call widget 1 widget 2 or widget 3. But this is not working and I don't know why exactly.
I have this videos collection where users videos are uploaded with 3 hashtags and what I want is that the user can search for one hashtag no matter which one, but it always shows all 3 hashtags instead of the one which the user searched for. And that is what I mean with 3 different widgets.
Here is my code:
class Openalldocs extends StatefulWidget {
final TextEditingController searchinginput;
static const route = '/openalldocs';
const Openalldocs({Key key, this.searchinginput}) : super(key: key);
#override
_OpenalldocsState createState() => _OpenalldocsState();
}
class _OpenalldocsState extends State<Openalldocs> {
List _allResults = [];
List _resultsList = [];
Future resultsLoaded;
bool nosuerfound = false;
String searchresult;
#override
void initState() {
super.initState();
widget.searchinginput.addListener(_onsearchChanged);
setState(() {
nosuerfound = true;
});
}
#override
void dispose() {
widget.searchinginput.removeListener(_onsearchChanged());
super.dispose();
}
#override
void didChangeDependencies() {
widget.searchinginput.text;
resultsLoaded = getusers();
super.didChangeDependencies();
}
_onsearchChanged() {
setState(() {
nosuerfound = false;
});
searchResults();
}
searchResults() {
var showResults = [];
if (widget.searchinginput.text != "") {
for (var tripsnapshot in _allResults) {
var title = DatbaseService.instance
.videosfromsnapshot(tripsnapshot)
.hashtag1
.toLowerCase();
print(title);
var title2 = DatbaseService.instance
.videosfromsnapshot(tripsnapshot)
.hashtag3
.toLowerCase();
print(title);
var title3 = DatbaseService.instance
.videosfromsnapshot(tripsnapshot)
.hashtag2
.toLowerCase();
print(title);
if (title.contains(widget.searchinginput.text.toLowerCase()) ||
title2.contains(widget.searchinginput.text.toLowerCase()) ||
title3.contains(widget.searchinginput.text.toLowerCase())) {
setState(() {
nosuerfound = true;
});
showResults.add(tripsnapshot);
}
}
} else {
setState(() {
nosuerfound = true;
});
showResults = List.from(_allResults);
}
setState(() {
_resultsList = showResults;
});
}
getusers() async {
var firestore = FirebaseFirestore.instance;
QuerySnapshot qn = await firestore.collection('videos').get();
if (!mounted) return;
setState(() {
_allResults = qn.docs;
});
searchResults();
return "Complete";
}
#override
Widget build(BuildContext context) {
final user = Provider.of<Userforid>(context);
if (nosuerfound == true) {
return ListView.builder(
itemCount: _resultsList.length,
itemBuilder: (BuildContext context, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () {
},
child: Column(
children: <Widget>[
Column(
children: [
HighlightedMatchesText(
searchString: widget.searchinginput.text,
content: _resultsList[index].data()['hashtag1'],
),
],
),
SizedBox(height: 3),
],
),
),
SizedBox(height: 6),
InkWell(
onTap: () {
},
child: Column(
children: <Widget>[
Column(
children: [
HighlightedMatchesText(
searchString: widget.searchinginput.text,
content: _resultsList[index].data()['hashtag2'],
),
],
),
],
),
),
SizedBox(height: 6),
InkWell(
onTap: () {
},
child: Column(
children: <Widget>[
Column(
children: [
HighlightedMatchesText(
searchString: widget.searchinginput.text,
content: _resultsList[index].data()['hashtag3'],
),
],
),
SizedBox(height: 3),
],
),
),
SizedBox(height: 6),
]);
},
);
} else {
return Padding(
padding: const EdgeInsets.fromLTRB(0, 30, 0, 0),
child: Center(
child: Container(
child: Text(
"No Hashtag found",
style: TextStyle(fontSize: 16),
)),
),
);
}
}
}

Your onTap handlers are empty, so nothing will happen actually when tapping.
To achieve what you are trying to, it is better to instead of creating widgets one by one in the Column children, create a for loop, and make the onTap and everything relative to it.
Here is how to achieve it (I took only a subsection of the code, the Column part):
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// the AMOUNT is how many hashtags you want to show
for (var i = 0; i < AMOUNT; i += 1) ...[
// the SizedBox will only exist between the elements in the list
// as before
if (i != 0) SizedBox(height: 6),
// create a builder to allow declaring a variable
Builder(
builder: (context) {
// declare the hashtag variable
final hashtag = 'hashtag$i';
return InkWell(
onTap: () {
// do something with the hashtag stored in the variable
// this will make it relative to the element in the list
},
child: Column(
children: <Widget>[
// why is there a Column inside another with only one child?
// I would recommend to remove it
Column(
children: [
HighlightedMatchesText(
searchString: widget.searchinginput.text,
// notice how I am using the hashtag variable here
// instead of a constant? ('hashtag1'), by the way
// the for loop will make the hashtag start at 0
// you can change it by increment in the declaration
// `final hashtag = 'hashtag${i+1}'`, if you want
// the existing behavior
content: _resultsList[index].data()[hashtag],
),
],
),
// what is this? if it is to add more space between the items
// in the list, I recommend removing it from here, and add it
// to the first `SizedBox` in the for loop
// in case you do that, the Column that this widget belong
// would also only now contain one widget, so, there is no
// need to have it
SizedBox(height: 3),
],
),
),
},
);
],
],
);
I added a lot of comments, I hope they help you to achieve what you are trying to.

Related

how to link flutter with firebase?

I am a flutter programmer and I want to learn Firebase and link it to flutter, now I was able to create the following code that allows the user to add the number of units he wants, so that every time he enters the name of the unit and chooses its number, then it sends all the information to Firebase How do I complete this code so that the user can send the information he entered to Firebase?
My code
class _UnitesPageState extends State<UnitesPage> with TickerProviderStateMixin {
var _myWidgets = <Widget>[];
int _index = 0;
final unitesnumber = [
' unite 1 ',' unite 2 ',' unite 3 ',
];
bool autoValidate = true;
GlobalKey<FormBuilderState> _formKey = GlobalKey<FormBuilderState>();
final Map<int, String> namesvalues = Map();
final Map<int, String> unitesvalues = Map();
final List<TextEditingController> _namesControllers = [];
final List<TextEditingController> _unitesControllers = [];
void _add() {
int keyValue = _index;
_myWidgets = List.from(_myWidgets)
..add(Container(
child: Column(
children: <Widget>[
_names(keyValue),
_unites(keyValue),
],
),
));
setState(() => ++_index);
}
#override
Widget build(BuildContext context) {
final bottomNavigationBar = Container(
child: Row(
children: <Widget>[
FlatButton.icon(
label: const Text(' SEND',
)),
onPressed: () async {
setState(() {
autoValidate = !autoValidate;
});
for (var i = 0; i < _myWidgets.length; i++) {
Map<String, dynamic> data = {
"Widgets Number":_myWidgets.length,
"names": _namesControllers[i].text,
"unites":_unitesControllers[i].text,
};
}
}
),
],
),
);
return Scaffold(
// appBar
bottomNavigationBar: bottomNavigationBar,
body:Padding(
child: Form(
autovalidateMode: AutovalidateMode.disabled,
key: _formKey,
child: Stack(
children: <Widget>[
Column(
children: <Widget>[
_buildfaculte(),
Expanded(
child: SizedBox(
child: ListView(
addAutomaticKeepAlives: true,
children: _myWidgets,
),
),
),
],
)
],
),),
),
);
}
Widget _names(int keyValue) {
TextEditingController controller = TextEditingController();
_namesControllers.add(controller);
return FormBuilderTextField(
name: 'names',
controller: controller,
);
}
Widget _unites(int keyValue) {
TextEditingController controller = TextEditingController();
_unitesControllers.add(controller);
return Container(
alignment: Alignment.center,
child: Autocomplete<String>(
optionsBuilder: (TextEditingValue value) {
return unitesnumber.where((suggestion) =>
suggestion.toLowerCase().contains(value.text.toLowerCase()));
},
onSelected: (value) {
setState(() {
_selectedUnites = value;
});
},
),
);
}
}

ListView.builder only loads after hot-reloading flutter app

When a user logs into my flutter app, they have to log in, then they are brought to a screen with a feed of posts. I use a ListView.builder to take a list of posts from my database and create the feed of posts. My issue is that when the feed screen is initially launched, the ListView doesn't load. As soon as I hot-reload the app the list does load. I imagine there's a very obvious minor mistake in my code but I just can't find it. I will put all of the code from the feed screen below, please take a look and let me know if you see the mistake.
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
static const String id = "home_screen";
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
// List allposts = [(post: Post, owner: String)];
Color _likeButtonColor = Colors.black;
Widget _buildPost(String username, String imageUrl, String caption) {
return Container(
color: Colors.white,
child: Column(
children: [
Container(
height: 50,
color: Colors.deepOrangeAccent[100],
child: Row(
children: [
SizedBox(width: 5),
CircleAvatar(),
SizedBox(width: 5),
Text(username, style: TextStyle(fontSize: 15)),
SizedBox(width: 225),
Icon(Icons.more_horiz)
],
),
),
Stack(
children: [
Image.asset("images/post_background.jpg"),
Padding(
padding: const EdgeInsets.all(20.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.network(imageUrl, fit: BoxFit.cover)),
),
],
),
Container(
height: 100,
child: Column(
children: [
const SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
onPressed: () {
setState(() {
HapticFeedback.lightImpact();
});
},
icon: Icon(Icons.thumb_up_alt_outlined, size: 30)),
Text("l", style: TextStyle(fontSize: 30)),
Icon(Icons.ios_share, size: 30)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(caption, style: const TextStyle(fontSize: 15))
],
)
],
),
)
],
),
);
}
List<Post> listPosts = [];
fetchPosts() async {
final userRef = FirebaseFirestore.instance.collection('users');
final QuerySnapshot result = await userRef.get();
result.docs.forEach((res) async {
print(res.id);
QuerySnapshot posts = await userRef.doc(res.id).collection("posts").get();
posts.docs.forEach((res) {
listPosts.add(Post.fromJson(res.data() as Map<String, dynamic>));
});
});
}
#override
void initState() {
fetchPosts();
print(listPosts);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: listPosts.length,
itemBuilder: (BuildContext context, int index) {
// We retrieve the post at index « index »
final post = listPosts[index];
// Replace with your actual implementation of _buildPost
return _buildPost(post.id, post.postUrlString, post.caption);
}),
);
}
}
The reason is that you need to rebuild your screen to show the reflected changes after performing an async operation (use setState to rebuild the UI). And secondly .forEach loop is not built to carry async stuff and are less efficient then a normal for loop so its better to change it.
fetchPosts() async {
final userRef = FirebaseFirestore.instance.collection('users');
final QuerySnapshot result = await userRef.get();
for(var res in result.docs)async{
print(res.id);
QuerySnapshot posts = await userRef.doc(res.id).collection("posts").get();
posts.docs.forEach((res) {
listPosts.add(Post.fromJson(res.data() as Map<String, dynamic>));
});
}
setState((){});//call it after end of your function
}
Ps:- You can use a variable named loading to show progress indicator and set it to false after fetching data in setState.

removing previous value and adding new in firestore list flutter

Here in firestore I want to update list with new values entered by the user and to remove all previous values. Suppose user add 2 new values [American English, French]. What I want is to remove all the values in the list and update the list with these values. I have used set and update method and it is just adding new values in newer index but not removing previous.
here is my code.
addCategoriesAndSkillsInDB({List categories, List skills}) async {
print('$skills');
categories == null
? _firestore
.collection('users')
.doc(getCurrentUser().uid)
.set({'skills': skills})
: _firestore
.collection('users')
.doc(getCurrentUser().uid)
.update({'categories': FieldValue.arrayUnion(categories)});
}
and that is how I am retaining new values in the list
import 'file:///E:/flutterProject/filmmaker/lib/auth_screens/signUp_screens/worker/signUp_screen5.dart';
import 'package:filmmaker/auth_screens/signUp_screens/worker/signUp_screen14.dart';
import 'package:filmmaker/logic/bloc/fields/fields_bloc.dart';
import 'package:filmmaker/resources/repo/firebase_repo.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class SignUpScreen4 extends StatefulWidget {
bool edit = false;
SignUpScreen4([this.edit]);
#override
_SignUpScreen4State createState() => _SignUpScreen4State();
}
class _SignUpScreen4State extends State<SignUpScreen4> {
List<String> _dynamicChips = [];
String _value;
final key = GlobalKey<FormState>();
final controller = TextEditingController();
#override
void dispose() {
// TODO: implement dispose
super.dispose();
controller.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Sign Up Screen 4'),
Form(
key: key,
child: TextFormField(
controller: controller,
validator: (value) =>
value.trim().isEmpty || value == null ? 'Empty Text' : null,
autofocus: true,
autocorrect: true,
enableSuggestions: true,
decoration: InputDecoration(
hintText:
'Type things like: Final Cut Pro, or Documentary making',
hintStyle: TextStyle(fontStyle: FontStyle.italic),
labelText: 'Tell us about some of your skills',
),
),
),
MaterialButton(
onPressed: () {
if (key.currentState.validate()) {
if (!_dynamicChips.contains(controller?.text)) {
setState(() {
_value = controller?.text;
});
_dynamicChips.add(_value);
controller.text = '';
}
}
},
child: Text("Add"),
),
dynamicChips(),
BlocConsumer<FieldsBloc, FieldsState>(builder: (context, state) {
if (state is FieldsInitial) {
return Container();
} else if (state is FieldSuccessfulState) {
return Container();
} else if (state is FieldUnsuccessfulState) {
return Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.error,
color: Colors.red,
),
SizedBox(
width: 5.0,
),
Text(
state.message,
style: TextStyle(color: Colors.red),
),
],
));
}
return Container();
}, listener: (context, state) {
if (state is FieldSuccessfulState)
widget.edit
? Navigator.of(context).push(
MaterialPageRoute(builder: (_) => SignUpScreen14()))
: Navigator.of(context).push(
MaterialPageRoute(builder: (_) => SignUpScreen5()));
}),
ElevatedButton(
onPressed: () {
BlocProvider.of<FieldsBloc>(context)
.add(NextButtonEventScreen4(_dynamicChips));
},
child: Text('Next'))
],
),
),
);
}
dynamicChips() {
return Wrap(
spacing: 6.0,
runSpacing: 6.0,
children: List<Widget>.generate(
_dynamicChips?.length,
(int index) => Chip(
label: Text(_dynamicChips[index]),
onDeleted: () {
setState(() {
_dynamicChips.removeAt(index);
});
},
)),
);
}
}
You need to pass List instead of String. For example
List<String> languages = ['English', 'Nepali', 'hindi'];
and then,
_firestore
.collection('users')
.doc(getCurrentUser().uid)
.update({'other languages': languages});

Flutter/Dart - type 'List<DropdownMenuItem<dynamic>>' is not a subtype of type 'List<DropdownMenuItem<String>>

I am trying to create a drop down list inside an alert dialog widget. The menu items need to be pulled from firebase. So far, I have created my alert dialog, looped through my firebase data and created a list from the results. The issue I am facing comes when I try to use my list as the "items" for my dropdown, when I run my code I get the following error:
type 'List<DropdownMenuItem<dynamic>>' is not a subtype of type 'List<DropdownMenuItem<String>>'
Here is my code:
class ViewSingleCard extends StatefulWidget {
final String imgUrl;
final String message;
ViewSingleCard({this.imgUrl, this.message});
#override
_ViewSingleCardState createState() => _ViewSingleCardState(imgUrl, message);
}
class _ViewSingleCardState extends State<ViewSingleCard> {
String imgUrl;
String message;
_ViewSingleCardState(this.imgUrl, this.message);
PageController _pageController = PageController(initialPage: 0);
int currentPage = 0;
#override
void dispose() {
super.dispose();
_pageController.dispose();
}
_onPageChanged(int index) {
setState(() {
currentPage = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepPurpleAccent,
title: Text('Viewer'),
actions: [
Stack(
children: [
IconButton(
icon: Icon(Icons.add),
onPressed: () {
createAlertDiaglog(context);
})
],
)
],
),
body: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: <Widget>[
PageView(
scrollDirection: Axis.horizontal,
controller: _pageController,
onPageChanged: _onPageChanged,
children: [
Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Image(
image: FirebaseImage(imgUrl,
maxSizeBytes: 15 * 1024 * 1024))),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Text(message),
),
),
],
),
Stack(
children: <Widget>[
Container(
margin: const EdgeInsets.only(bottom: 35),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
for (int i = 0; i <= 1; i++)
if (i == currentPage)
SlideDots(true)
else
SlideDots(false)
],
),
),
],
),
]),
);
}
createAlertDiaglog(BuildContext context) {
String selectedOccasion;
List<DropdownMenuItem> occasions = [];
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Add to collection"),
content: StreamBuilder<QuerySnapshot>(
stream: getCollectionInfo(context),
// ignore: missing_return
builder: (context, snapshot) {
if (!snapshot.hasData)
const Text("Loading.....");
else {
for (int i = 0; i < snapshot.data.docs.length; i++) {
DocumentSnapshot snap = snapshot.data.docs[i];
occasions.add(
DropdownMenuItem(
child: Text(
snap.id,
),
value: "${snap.id}",
),
);
}
}
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// ignore: missing_return
DropdownButton<String>(
items: occasions,
hint: Text("Style"),
value: selectedOccasion,
onChanged: (String Value) {
setState(() {
selectedOccasion = Value;
});
},
),
],
);
}),
);
});
}
Stream<QuerySnapshot> getCollectionInfo(BuildContext context) async* {
yield* FirebaseFirestore.instance
.collection('collections')
.doc(FirebaseAuth.instance.currentUser.uid)
.collection('occasions')
.snapshots();
}
}
Any help? Thanks
Here's the fix, add the <String> there:
occasions.add(
DropdownMenuItem<String>(
child: Text(
and also fix the type of the list (thanks to #nvoigt's answer)
List<DropdownMenuItem<String>> occasions = [];
Your DropDownButton is given the <String> type, so it's expecting the same thing from its items.
Whenever you get this exception, just swap the locations of the two types and think of an assignment. This means you are trying to do this kind of assignment
List<DropdownMenuItem<String>> a;
List<DropdownMenuItem<dynamic>> b;
a = b;
This:
List<DropdownMenuItem> occasions = [];
is a List<DropdownMenuItem<dynamic>>, but you want a List<DropdownMenuItem<String>>, so you need to make it one:
List<DropdownMenuItem<String>> occasions = [];
That said: you have an analyzer. Do not ignore it's warnings. You have ignored warnings that are correct, where you have made a mistake. Do not do this. Do not ignore your mistakes, fix them.

How to inner-join in firestore

I want to build a view to show some events inside a listview in my app like this:
I have these two tables:
Users
 
Events
But I don't know how do a "inner join" between the tables USERS and EVENTS...
I tried this:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:project/Methods.dart';
import 'package:project/Views/CadastroUsuario.dart';
import 'dart:math';
class EventClass{
String owner;
String description;
String city;
String state;
String place;
}
class EventsListing extends StatefulWidget {
#override
EventsListingState createState() => new EventsListingState();
}
class EventsListingState extends State<EventsListing> {
List<EventClass> events;
#override
void initState() {
super.initState();
events = new List<EventClass>();
}
void buildEventClass(DocumentSnapshot doc) async {
EventClass oneEvent = new EventClass();
DocumentReference document = Firestore.instance.collection("users").document(doc["userid"]);
document.get().then((DocumentSnapshot snapshot){
oneEvent.owner = snapshot["name"].toString();
});
oneEvent.description = doc["description"];
oneEvent.place = doc["place"];
oneEvent.city = doc["city"];
oneEvent.state = doc["state"];
events.add(oneEvent);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Events'),
),
body: new StreamBuilder(
stream: Firestore.instance.collection("events").snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if (snapshot.connectionState == ConnectionState.waiting)
return Text("Loading...");
return new ListView(
padding: EdgeInsets.only(left: 5.0, right: 5.0, top: 5.0),
children: snapshot.data.documents.map((document){
buildEventClass(document);
return events.length == 0 ? new Card() : item(events.last);
}).toList()
);
},
),
floatingActionButton: new FloatingActionButton(
tooltip: 'New',
child: new Icon(Icons.add),
onPressed: () async {
Navigation navigation = new Navigation();
navigation.navigaTo(context, CadastroUsuario());
},
),
);
}
Widget item(EventClass oneEvent) {
return new Card(
elevation: 4.0,
child: new Column(
children: <Widget>[
new Row(
children: <Widget>[
new Column(
children: <Widget>[
new Text(oneEvent.owner.toString(),
style: TextStyle(fontSize: 20.0),
overflow: TextOverflow.ellipsis,),
],
),
new Column(
children: <Widget>[
],
)
],
),
new Container(
color: Colors.blue,
height: 150.0,
),
new Row(
children: <Widget>[
new Row(
children: <Widget>[
new Text(oneEvent.description.toString(),
style: TextStyle(fontSize: 20.0),
overflow: TextOverflow.ellipsis,),
],
),
new Row(
children: <Widget>[
new Text(oneEvent.place.toString(),
style: TextStyle(color: Colors.grey[350]),
overflow: TextOverflow.ellipsis,),
],
),
new Row(
children: <Widget>[
new Text(oneEvent.city.toString() +' - '+ oneEvent.state.toString(),
style: TextStyle(color: Colors.grey[350]),
overflow: TextOverflow.ellipsis,),
],
)
]
)
],
)
);
}
}
But every time that I try to show these events I get this exception
Exception has occurred.
PlatformException(error, Invalid document reference. Document references must have an even number of segments, but users has 1, null)
What I'm doing wrong? How I can do a "inner join" between thesse tables and show the events?
I'm using the Firebase Firestore.
PS: I already know that Firestore is a noSQL database and have no "joins", but I want to do something like a join.
As I was telling in the coments Firestore does not support multi collection querys cause its no relational DB. If you need to access multiple collections you would manage querys independently.
This is how I usually get related collections data (Sorry this is JS code but I dont know DART):
var data = {};
//First you get users data
DocumentReference document = Firestore.collection("users")
document.get().then((snapshot) => {
//In this case I will store data in some object, so I can add events as an array for a key in each user object
snapshot.forEach((userDoc) => {
var userDocData = userDoc.data()
if (data[userDoc.id] == undefined) {
data[userDoc.id] = userDocData
}
})
//So in this moment data object contains users, now fill users with events data
//In this var you count how many async events have been downloaded, with results or not.
var countEvents = 0
Object.keys(data).forEach((userDocId) => {
//Here Im creating another query to get all events for each user
SnapshotReference eventsForCurrentUserRef = Firestore.collection("events").where("userId", "==", userDocId)
eventsForCurrentUserRef.get.then((eventsForUserSnapshot) => {
//Count events
countEvents++
eventsForUserSnapshot.forEach((eventDoc) => {
var eventDocData = eventDoc.data()
//Check if array exists, if not create it
if (data[eventDocData.userId].events == undefined) {
data[eventDocData.userId].events = []
}
data[eventDocData.userId].events.push(eventDocData)
})
if(countEvents == Object.keys(data).length){
//Lookup for events in every user has finished
}
})
})
})

Resources