Fetch all the posts of all the users from Cloud Firestore - firebase

I am building a Flutter app. Cloud firestore database structure is given in the picture. I want to get all the posts of all the users using a StreamBuilder. How can I do that? So far I have tried this :
Stream<List<PostModel>> jobs() {
return usersCollection.snapshots().map((snapshot) {
return snapshot.documents.map((doc) {
doc['posts'].map((docu) {
return PostModel.fromSnapshot(docu);
});
}).toList();
});
}

If you want all the document in all of the subcollections called "posts" (for all users), then you probably want a collection group query using collectionGroup():
db.collectionGroup("posts").snapshots()...
This will give you all documents in any collection or subcollection called "posts", no matter where it's nested.

Related

Get detail information from master-detail collection in firestore

I have created a simple app using flutter and firebase firestore database. There are 'users' collections and each user has 'posts' collections. Each post may have one or more posts added by different users.
I am trying to get all the posts regardless of users. However, my current function was written for reading records only shows the posts relevant for login user, not all the posts.
Stream<QuerySnapshot> readItems({required String collectionName}) {
CollectionReference detailCollection = _firestore
.collection(mainCollectionName!)
.doc(userUid)
.collection(collectionName);
return detailCollection.snapshots();
}
Here, I pass 'users','login user's uid' and 'posts' as mainCollectionName, userUid and collectionName respectively. Can anybody guide me how do I get all the posts regardless of users?
After searching I found a solution here. The following method gives the desired output.
Stream<QuerySnapshot> readItems({required String collectionName}) {
Query<Map<String, dynamic>> detailCollection = _firestore.collectionGroup(collectionName);
return detailCollection.snapshots();
}
It is possible to get all sub collections data from all the documents in a collection. Try this way
_firestore
.collection(`${mainCollectionName}/*/${collectionName}`)
.get()
Refer to this page for more details about querying collections and sub collections - https://firebase.googleblog.com/2019/06/understanding-collection-group-queries.html

Get collections in subcollections and subcollections

I have a problem with the firestore. The problem is that I have such a database. And I'd like to download all the stuff in the hives collection. The problem is that there are different collections for each of the apiaries. I have, for example: 3 documents in apiaries and for each apiaries and in each document I have, for example: 5 hives. And I would like all the details from all the hives.
users:
{uid}:
apiaries:
{uid}:
hives:
{uid}
notes:
{uid}
If you want to get all of the documents in all of the subcollections named "hives", no matter where they are nested, then you will want to use a collection group query.
firebase.firestore().collectionGroup("hives").get()
I wrote this. Is this fairly correct? Do I have to change anything in the database?
async getHives() {
await fb.usersCollection
.doc(fb.auth.currentUser.uid)
.collectionGroup('hives')
.onSnapshot(snapshot => {
let hivesArray = [];
snapshot.forEach(doc => {
let hive = doc.data();
hive.id = doc.id;
hivesArray.push(hive);
});
store.commit('setHives', hivesArray);
});
},

Flutter Firebase Cloud Firestore How to filter a stream with where() query using a subcollection

So i have in my Cloud Firestore I have a collection of recipes that contains documents(with casual ids) with different recipes. Every document has a 2 fields with the recipe name and the recipe duration.
Every document has also a collection named likedBy where there is documents that have as ids user ids and have a single field with the date of the like.
Now i want to return all recipes that have in their likedBy subCollection the userId.
i' ll write what i' ve tried with only essential code.
String userId= 'uiuu4fn3fff4fu';
Scaffold(
body:StreamBuilder(
stream: THE STREAM THAT I NEED,
builder:(context,snapshot){
return ListView.builder(
itemCount: snapshot.data.documents.length
itemBuilder:(context,index){
return Column(children:[
Text(snapshot.data.documents[index]['recipeName']),
Text(snapshot.data.documents[index][recipeDuration]),]) } ) } ) )
What i want is to return only documents that have in their likedBy subCollection a specific user uid.
I' ve tried with this stream
Firestore.instance.collection('recipes').parent().collection('likedBy').where(FieldPath.documentId,
isEqualTo,userId).snapshots()
But it doesn' t work and i have no idea what else i can try.
Any help is highly apprecieted.
Items should not be added by the users but by admins, that means that there will be a list of items added by admins and a list of users that can add them in favorites and what i want to achieve is that users can see all their favorites in the order in which they saved them. To be clear i want something like Instagram functionality to save posts.
So you want a way to query subcollection. To do that simply use collectionGroup method:
db.collectionGroup('likedBy').where('userId', '==', '1');
To order by a value use timestamp:
// add to your document
db.collection("items")
.add({...item, created: firebase.firestore.Timestamp.fromDate(new Date()) })
and to orderby this value use orderby:
db.collection("items")
.orderBy("created", "asc")
What you might want to do instead is have a 'likedBy' property on the recipe document instead of its own sub-collection. If it is just a list of userids that should be no problem. Then you can just say recipeCollection.where(likedBy, array contains: userId)

Change nested sub-collections on CloudFunctions

I need help with something.
I have 2 collections on my project, one is called products and another called stores.
One product can belong to many stores, so to make the app more “performatic”, I’m duplicating the selected product information into a sub-collection of stores, in this case stores > products.
My idea is to create a cloud-function that will watch for any updates on any product and then reflect those changes on the stores > products sub-collection by updating the values.
I’m already saving it with the same ID. So for example, the productID 1 under the products collection will have the same id under the stores > products sub-collection.
My question is, how can I query only the products sub-collection? Is this possible?
It depends what do you exactly want to query.
If you want to query only ONE specific product document within the products sub-collection of ONE given store document you would do as follows:
var docRef = db.collection("stores").doc(storeId).collection("products").doc(productId)
docRef.get().then(function(doc) {
if (doc.exists) {
console.log("Document data:", doc.data());
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
});
If you want to query the products sub-collection of ONE given store (getting all the products docs within this sub-collection) you would do as follows:
db.collection("stores").doc(storeId).collection("products").get()
.then(function(querySnapshot) {
//....
})
.catch(function(error) {
//....
});
If you want to query the products sub-collections of ALL the stores, you would use a Collection Group Query, as follows:
var productsCollGroup = db.collectionGroup('products');
productsCollGroup.get()
.then(function (querySnapshot) {
//....
})
.catch(function(error) {
//....
});
You can check the thread on this link [1], specifically to your question you can check this answer [2].
For example they mention have an array of documents and they provide the answer of how to search for an specific document within a collection.
[1] Firestore query subcollections
[2] https://stackoverflow.com/a/46585748/9054282

Firestore: remove sensitive fields on documents

I'm trying to figure it out how to remove a sensitive field on a firestore document. For example, my collection is a group information. The group is protected with a pin code field. Any one wants to join the group has to know the pin code.
In the meantime, I want to let users query what group is available to join. For query part, I don't want return group information with pin code information. Do we have anyway to remove sensitive fields from a document for Firestore for reading event?
Cloud function only supports write event. 1 possible solution is use cloud function on write event, and put pin code in a separate document. Is there a better solution? THanks.
My group schema is:
group: {
name: string,
pinCode: string
}
A user can either access a document, or they can't. There is no property-level access control in Firestore.
So to accomplish what you want, you will need to store the public and private information in separate documents.
You could either create a second document with the private information in the same collection and then secure them using:
match /databases/{database}/documents {
match /groups/{group} {
allow read: if resource.data.visibility != "private"
}
}
Alternatively (and simpler to secure) you could create a separate collection for the private documents.
You can create a Firebase Function that returns only the fields that you need (non sensitive), here an example:
exports.getTopUsers = functions.https.onCall(async (data) => {
const users = [];
return db.collection('users').orderBy('bids').limit(data.limit).get()
.then((querySnapshot) => {
querySnapshot.forEach((user) => {
users.push({
diplayName: user.get('displayName'),
});
});
return {
topUsers: users,
};
})
.catch((err) => {
console.error(err);
});
});
So, you need to create a separate array (that will be returned) and filling it with only the field that you want while iterating your Firestore collection.

Resources