How do i create a timeline feed using firebase in flutter? - firebase

- posts
- userID
- userID
- randomID
- randomID
- followers
- personB userid
- personA userid
- following
- personA userid
- personB userid
This is how my firebase collection is organized.
how do i get create a timeline feed for current logged-in user where the timline posts should be of only from the logged-in user's following list?
Note:I dont want to use firebase functions.Is it possible with CRUD?
What ive tried so far.
getFollowing() async {
QuerySnapshot snapshot = await followersRef
.document(currentUser.id)
.collection('userFollowing')
.getDocuments();
setState(() {
followingList = snapshot.documents.map((doc) => doc.documentID).toList();
print(followingList);
});
}
getTimeline()async{
QuerySnapshot snapshot = await postsRef
.document(followingList)//getting an error here saying list<string> csn't be assigned to string.
.collection('userPosts')
.orderBy('timestamp', descending: true)
.getDocuments();
List<Post> posts =
snapshot.documents.map((doc) => Post.fromDocument(doc)).toList();
setState(() {
this.posts = posts;
});
}

The approach which I think is efficient is using A collection 'Posts' and document for each post, with an array inside the post document as a field.
This means when a user adds post you have to include the user's followers as a field(List<dynamic) inside the post.
- posts(Collection)
- post(Document)
- followers(List<dynamic>)
you can query post for users like
Firestore.instance.collection('posts').where('followers', arrayContains: currentUserId).snapshots();
//this brings all queries with the tagged users as followers aka the users that follow the poster will be able to query this post.
if you want to update the array you can use
FieldValue.arrayRemove or FieldValue.arrayUnion,
Edit: As a final warning I must mention that there is a limit to how much data there could be for one document, based on the scale of your app you have to decide whether to put a growing list (such as followers) inside one document or to create another collection for the growing list and give one document for each element since documents can't be limited (this approach could cost more).

List timelinePosts =[];
getFollowing() async {
QuerySnapshot snapshot = await followersRef
.document(currentUser.id)
.collection('userFollowing')
.getDocuments();
setState(() {
followingList = snapshot.documents.map((doc) => doc.documentID).toList();
print(followingList);
});
}
getTimeline()async{
List posts = [];
for( int i=0; i< followingList.length; i++)
{
QuerySnapshot snapshot = await postsRef
.collections('posts/${followingList[i]}/userPosts')
.orderBy('timestamp', descending: true)
.getDocuments();
posts+= snapshot.data.documents.map((doc) => {'id':doc.documentID,...doc.data}).toList();
}
setState(() {
timelinePosts = timeLinePosts + posts;
});
}
then u can use Listview.builder() on timelinePosts,
However this is not the most efficient method, since you are fetching all the posts at once. You can also implement fetch post as you scroll through the list, using Listview controller attribute

Related

How to also update user's name and image in comments sub-collection in Flutter via Firestore

In my app, users can comment on every post and the comments are stored in the post's sub-collection: 'comments'. Each comments' document contains the poster's username, profile image, user Id, comment Id and some other fields.
So I'm trying to also update each comments' document that contains a current user's userId when that user updates their profile.
I have only been able to achieve the code below;
//Uploading the new image to storage
final firebaseUser = FirebaseAuth.instance.currentUser!;
final String uids = firebaseUser.uid;
final Reference storageReference =
FirebaseStorage.instance.ref().child("userImages- $uids");
UploadTask uploadTask = storageReference.putFile(imageTemp);
String downloadUrl = await (await uploadTask).ref.getDownloadURL();
//Updating users' document with the new image
final CollectionReference users =
FirebaseFirestore.instance.collection("users");
final String uid = firebaseUser.uid;
String url = downloadUrl;
await users.doc(uid).update({'url': url});
//Trying to also update users' comments document with the image
final CollectionReference posts =
FirebaseFirestore.instance.collection("posts");
await posts
.doc()
.collection('comments')
.doc()
.update({'profilePic': url});
How can I possibly achieve this? Any help will be appreciated.
You could do something like this
await users.doc(uid).update({'url': url}).then((value2) {
FirebaseFirestore.instance
.collection('posts')
.doc('postDOCID')
.collection('comments')
.where('uid', isEqualTo: curUserUID)
.get()
.then((value) => value.docs.forEach((element) {
element.data().update('userImageURL', (value) => "url");
}));
});
Basically, what you will need to do is loop through or search with where through post documents where userId = currentUpdatedUID.
Once you find it, loop the list and update each one of them.
Let me know if any issue comes up.
Cheers!!

Firebase query doesn't get documents with a specific field

I'm running a query to get all documents from firebase containing a field of location contains, say 'Nairobi'. The structure of my database is /posts/[userId]/userPosts/[postId].
Now, when I specify the userId in my code, I get the documents.
QuerySnapshot snapshot = await FirebaseFirestore.instance.collection('posts')
.doc("1092987983578079255")
.collection('userPosts')
.where('location', isGreaterThanOrEqualTo: '${placemark.locality}')
.get();
setState(() {
posts = snapshot.docs.map((doc) => Post.fromDocument(doc)).toList();
isLoading = false;
});
However, when I try to get all the documents within the entire posts collection, I get null results.
QuerySnapshot snapshot = await FirebaseFirestore.instance.collection('posts')
.where('location', isGreaterThanOrEqualTo: '${placemark.locality}')
.get();
setState(() {
posts = snapshot.docs.map((doc) => Post.fromDocument(doc)).toList();
});
I have tried using the code
QuerySnapshot snapshot = await FirebaseFirestore.instance
.collectionGroup("userPosts")
.where('location', isGreaterThanOrEqualTo: '${placemark.locality}')
.get();
setState(() {
posts = snapshot.docs.map((doc) => Post.fromDocument(doc)).toList();
isLoading = false;
});
but I get the error Operation was rejected because the system is not in a state required for the operation's execution. If performing a query, ensure it has been indexed via the Firebase console.
given that, it is only querying through one criterion, I don't believe that a composite index is necessary but I, still, have created one.
adb logcat doesn't give me the link to create an index even if I wrap the code in try to catch the error e.
What am I missing?

Flutter - Deleting a document in Firestore leads to the deletion of a random document and not the selected one

The 'utenti' (users) collection contains a document for each user which in turn contains the 'salvataggi' (saves) collection to save objects within the app.
Each document inside 'salvataggi' (saves) has an automatically generated id containing a series of data (String to be precise).
Documents within 'salvataggi' (saves) can be added by saving objects created from two other collections always in FIrestore.
When, through a button, I want to delete an object from the 'salvataggi' (saves) collection, a random document is deleted and not the one corresponding to the object.
Screenshot of Firestore
Object 1
final CollectionReference _usersRef =
FirebaseFirestore.instance.collection('utenti');
final User _user = FirebaseAuth.instance.currentUser;
//Add
Future _addToSaved() {
return _usersRef.doc(_user.uid).collection('salvataggi').doc().set({
'fonte': elenco.fonte,
'title': elenco.title,
'url': elenco.urlAvv,
'imageEv': elenco.urlAvv,
'p1': elenco.iconaProspettiva1,
'p1url': elenco.urlProspettiva1,
});
}
//Remove
Future _removeFromSaved() async {
CollectionReference userSaved =
_usersRef.doc(_user.uid).collection('salvataggi');
QuerySnapshot querySnap = await userSaved.get();
querySnap.docs[0].reference.delete();
}
Object 2
final CollectionReference _usersRef =
FirebaseFirestore.instance.collection('utenti');
final User _user = FirebaseAuth.instance.currentUser;
//Add
Future _addToSaved() {
return _usersRef.doc(_user.uid).collection('salvataggi').doc().set({
'fonte': widget.single.fonte,
'title': widget.single.title,
'url': widget.single.urlAvv,
'imageEv': widget.single.imageEvAvv,
'lastupdate': widget.single.dataAggiornamento,
'p1': widget.single.iconaProspettiva1,
'p1url': widget.single.urlProspettiva1,
});
}
//Remove
Future _removeFromSaved() async {
CollectionReference userSaved =
_usersRef.doc(_user.uid).collection('salvataggi');
QuerySnapshot querySnap = await userSaved.get();
querySnap.docs[0].reference.delete();
}
What am I doing wrong? Why does this happen?
When the user saves a document try saving the id of that document with it so whenever the user unsaved the document. You can pass the id of that unsaved document to firestore.
It will look something like this
Future _removeFromSaved(String docID) async {
CollectionReference userSaved =
_usersRef.doc(_user.uid).collection('salvataggi');
await userSaved.doc(docID).delete()
}
--UPDATE--
You can save document id by calling the then method after adding the document to firestore and then updating it
Future _addToSaved()async {
await _usersRef.doc(_user.uid).collection('salvataggi').add({
'fonte': widget.single.fonte,
'title': widget.single.title,
'url': widget.single.urlAvv,
'imageEv': widget.single.imageEvAvv,
'lastupdate': widget.single.dataAggiornamento,
'p1': widget.single.iconaProspettiva1,
'p1url': widget.single.urlProspettiva1,
}).then(docRef=>await _usersRef.doc(_user.uid).collection('salvataggi').doc(docRef.id).update({'id':docRef.id}));
}
querySnap.documents.first.reference.delete();
Use this instead of querySnap.docs[0].reference.delete();

How to get documents in firestore, whose document IDs are stored in the list?, i.e bring only those documents....?

I have a list that contains the document Ids of a particular collection "users", and I want to get documents only present in this list, and these documents are in "users" collection as mention before.
Code:
getUsers() async
{
double radius = 0.3;
String field = "GeoPosition";
print(currentUser.point.longitude);
GeoFirePoint center = geo.point(latitude: currentUser.point.latitude, longitude: currentUser.point.longitude);
var collectionRef = Firestore.instance.collection('user_locations').document(currentUser.pincode) .collection('Users_complete_address_and_geopoint');
this.stream = geo.collection(collectionRef: collectionRef).within(center: center, radius: radius, field: field, strictMode: false);
Future<List<certainrangeusers>> users1 = stream.first.then(
(documents) => documents.map((doc) => certainrangeusers(
id: doc['userPhone'],
)
).toList());
users1.then((val) async{
QuerySnapshot snapshot = await Firestore.instance.collection('users').where('id', isEqualTo: val.first.id).getDocuments();
List<User> users = snapshot.documents.map((doc) => User.fromDocument(doc)).toList();
setState(() {
this.users = users;
});
});
}
Firebase Structure:
Click here for the firebase structure
Code In image format:
Click here for the image
In orange box, "users1" is a list having document IDs...of users 10km users
In the pink box, we r using the value of the list...
In the green box, we need to pass the document ids present in the above list...
P.s: I am using "val.first.id" just to bring the document present at first in the list........But I need to bring every document present in that list...so that's a point I have struck...
Here how to search for all documents from the list id
instead of:
await Firestore.instance.collection('users').where('id', isEqualTo:
val.first.id).getDocuments();
use this:
await Firestore.instance.collection('users').where('id', whereIn:
val).getDocuments();
Since you have a list of certainchangeuser, do this to get the ids.
users1.then((val){
// Get the ids
List ids = [];
for (var value in val){
ids.add(value.id);
}
//Then
QuerySnapshot = await
Firestore.instance.collection('users').where('id',
whereIn:ids).getDocuments();
....
});
You can use a transaction for this purpose. Firestore transactions

How to get, set, update and delete data from the cloud firestore in Flutter?

I tried some code but getting an exception.
The Exception that I'm getting:
java.lang.IllegalArgumentException: Invalid document reference. Document references must have an even number of segments, but Users has 1
I searched for it, according to this, Document references must have an even number of segments like: Collection - document - Collection - document - Collection - document
Query for getting data from firestore:
String getIsNewUSer;
Firestore.instance.collection('Users').document(uid).get().then((DocumentSnapshot document){
print("document_build:$document");
setState(() {
getIsNewUSer=document['IsNewUser'];
print("getIsNewUSe:$getIsNewUSer");
});
});
Query for Updating data to the firestore:
Firestore.instance
.collection('Users')
.document(uid)
.updateData({
"IsNewUser":"1"
}).then((result){
print("new USer true");
}).catchError((onError){
print("onError");
});
These code line at I'm getting above Exception.
initState:
void initState() {
super.initState();
this.uid = '';
FirebaseAuth.instance.currentUser().then((val){
setState(() {
this.uid= val.uid;
print("uid_init: $uid");
});
});
}
Null safe code:
Get data:
var collection = FirebaseFirestore.instance.collection('collection');
var docSnapshot = await collection.doc('doc_id').get();
Map<String, dynamic>? data = docSnapshot.data();
Set data:
var collection = FirebaseFirestore.instance.collection('collection');
collection.add(someData);
Update data:
var collection = FirebaseFirestore.instance.collection('collection');
collection
.doc('foo_id') // <-- Doc ID where data should be updated.
.update(newData);
Delete data:
var collection = FirebaseFirestore.instance.collection('collection');
collection
.doc('some_id') // <-- Doc ID to be deleted.
.delete();
Replace this part in your queries:
Firestore.instance.collection('Users').document(uid)
with
Firestore.instance.document('Users/$uid')
Collection - document - Collection - document - Collection - document
Basically you already had the answer.
It is possible that FirebaseAuth.instance.currentUser() future didn't complete and populte this.uid. So this.uid == '' (empty string). So Firestore is throwing errror as you are trying to updated document at Users which is a collection.
You can validate this by printing this.uid before the update statement.
One way is to use helper method to update
Future<void> update(Map data) async {
final user = await FirebaseAuth.instance.currentUser();
return Firestore.instance.collection('Users').document(user.uid).updateData(data);
}
Then you can use helpr method as update({isNewUser: "1"}).then((r) {...})....
You can follow same approach for fetching the document as well.

Resources