I would like to know How I can fetch all documents from the "playgrounds" collection that are associated with a specific document in the "solutions" collection in my React app
I have the following collections:
"users": This collection contains user documents.
"solutions: This collection contains solution documents.
"playgrounds": This collection contains documents for different solutions in different languages. For example, a user submitted a solution in 2 different languages, such as React and Vue, so I'll create two documents in the playgrounds collection to store those solutions.
How can I fetch those two solutions in the corresponding solution document?
Please help me with that!
You can get the High-level overview of your database like below as per the Provided inputs
Store Solutions in the Playgrounds collections as a sub-collection of its documents
Playgrounds(Collection) Users(Collection)
├──Document(Playground) ├──Document
| └──pid | └──uid
| └──Solutions(sub-collection) ├──Document
| ├──Document(Solution) | └──uid
| | └──sid
| ├──Document(Solution)
| └──sid
Now to get a solutions of a particular Playground we just have to get the corresponding subcollection
Let’s say You are in Playground A and you need to get all solutions which is posted for Playground A you will do something like :
import { collection, getDocs } from "firebase/firestore";
const fetchSolutions = async (playgroundId = "A") => {
const playgroundRef = collection(db, "playgrounds", playgroundId, "solutions");
const solutions = await getDocs(playgroundRef);
solutions.forEach((solution) => {
console.log(solution.id, " => ", solution.data());
});
};
For more information go through this docs and this doc
Related
I have a collection named "departments" with a subcollection inside named "users". I want to delete all the documents in "departments" without documents in the users sub-collection or without the sub-collection users.
Any ideas of how to find the documents to delete?
Thanks!
Assuming you have a structure that looks like this:
Firestore-root
|
--- departments (collection)
|
--- $departmentId (document)
|
--- users (collection)
|
--- $uid (document)
|
--- //user data
To be able to achieve this:
I want to delete all the documents in "departments" without documents in the users sub-collection.
You have to get all documents in the users sub-collection and delete them. But remember, such an operation is not really recommended by the Firebase team to be done on the client, if you have a large number of documents inside your collection. However, for a small number of documents, it will work.
The most important thing in this operation is that if you delete those documents, the sub-collections will continue to exist, and deleted documents will be displayed in italic.
Only in the Realtime Database, if you delete a node, you delete it with all the data that exists beneath it. But here is not the case, so no worries.
To be able to delete documents that don't have subcollection, you must query the departments collection and iterate the documents to check whether they have the subcollection users on it. See sample code below:
const db = getFirestore();
// `departments` reference.
const departmentsRef = query(collection(db, "departments"));
// Gets all documents from the department's reference.
const querySnapshot = await getDocs(departmentsRef);
// Iterate the documents.
querySnapshot.forEach(async (doc) => {
// `users` reference.
const usersRef = query(collection(db, "departments", doc.id, "users"));
// Check if the document has the `users` collection
const querySnapshot = await getDocs(usersRef)
.then((usersDoc) => {
// Check if the `users` subcollection exists
// Also counts the documents of the subcollection.
if (!usersDoc.size) {
// Deletes the document from the document reference.
deleteDoc(doc.ref);
}
});
});
I am new to firebase cloud firestore and need help understanding it a bit.
I am working on a project of the following structure.
Each "Restaurant" document contains its own "products" subcollection.
Here, I wanted to run a query to get all the products by different
restaurants that contain the tag "coffee" and are in a specific
Pincode "234144".
I tried Collection group queries by adding Pincode to each product owned by a particular restaurant but changing a Pincode would cost a lot, as all products would have to be edited, I guess.
Is there any efficient way of doing it or is it not possible in this
database in an efficient way?
Please let me know what do you think... Thank you.
If I understand correctly, you want to retrieve all products with a certain tag and pincode (I suppose this is similar to a postal zipcode?). There really are only two alternatives that I can think of:
Collection group query
As you mention, you can store both tag and pincode in product documents. Then perform a single collection group query along these lines (pardon the javascript, but I am not familiar with Dart, it should be very similar):
var products = await firestore.collectionGroup('products')
.where('tag', '==', 'coffee')
.where('pincode', '==', '234144').get();
As you have noted, with this solution you need to keep pincode in each product This piece of data is duplicated and it is normal to feel that it should be avoided because it is wasteful and dangerous (can go out of sync), but this is the way to go! It is called denormalization. This is well explained in this video by Todd Kerpelman.
You can then create a Cloud Function triggered by restaurant update to keep pincode in products in sync with the corresponding pincode in restaurants
Query restaurants then products
To keep the pincode in restaurants only, you have to do your query in two steps: first filter restaurants in the certain pincode, then filter products by tag:
// 1 - retrieve restaurants in specific pincode
var restaurants = await firestore.collection('restaurants').where('pincode', '==', '234144').get();
// 2 - For each retrieved restaurant, retrieve all products matching the tag
var products = [];
for(let i = 0; i < restaurants.docs.length; ++i) {
var p = await restaurants.docs[i].collection("products").where("tag", "==", "coffee");
products.push(p);
}
With this method, no need to duplicate pincode in each product, however your queries are less optimal, because you load potentially useless restaurants that do not serve coffee in your pincode.
I have a similar data structure, and Louis Coulet's answer helped me a lot. However, I ran into an issue, as my node/firebase environment complained that restaurants.docs[i].collection was not a function. Instead, I had to use restaurants.docs[i].ref.collection.
So, in my case, here's the code that wound up working (using the original poster's "restaurants/products" data model as an example):
// 1 - retrieve restaurants in specific pincode
const restaurants = await firestore.collection('restaurants').where('pincode', '==', '234144').get();
// 2 - For each retrieved restaurant, retrieve all products matching the tag 'coffee'
const products = [];
for (let i = 0; i < restaurants.docs.length; i++) {
await restaurants.docs[i].ref
.collection('products')
.where('tag', '==', 'coffee')
.get()
.then(s => Promise.all(s.docs.map(d => {
products.push(d);
})));
}
I have found that I need to return the sub-collection contents via some kind of promise, otherwise, after I try to get the data in the variable -- products, in this case -- it just shows up as undefined.
After I populate the products variable, I am then able to read its contents like this:
products.forEach(p => {
console.log(p.data().name);
console.log(p.data().tag);
}
I hope someone finds this useful, and many, MANY thanks to Louis Coulet for sending me/us down the correct path with this sub-collection headache :-)
Here, I want to query by the value "ministoreid1" in Firebase console. But I am not able to figure out. Here, I am trying to do the query in console not using codes.
I have filed the feature request at Alex' suggestion. And the reply I received from Firebase Support:
Currently, there is no query similar to array-contains available in the Firestore Console. I can file a feature request ticket on your behalf. However, I can't guarantee anything at the moment, so please watch out for any updates on our blog or release notes for now. For the map field, you can try to filter on the console using the format: 'mapFieldName.keyName' in the field text box
So we can query for map values by 'mapFieldName.keyName'. I didn't know this before.
Here, I am trying to do the query in console not using codes.
Unfortunately, there is currently no way you can filter your documents in the Firebase console according to a value that exist in an array. As you can see, there are only the following operators:
== is equal to
> is after
>= is after and includes
< is before
<= is before and includes
But an whereArrayContains option it is not present yet. I recommend you file a feature request for that. It might be also useful for other developers.
The query that you perform in the console does't return any results because you are checking if the mini_stores_assigned is equal to ministoreid1, which obviously is not since the mini_stores_assigned property is an array and not a String so you can compare them.
For future use, Firebase has added the feature request by Ssuburat. You can now can filter your documents in the Firebase console according to a value that exist in an array.
###FILTER BLOGS BY USER.
for example if you have two collections (one to many)
/users
/blogs
blog and user has these schemes:
blog: { name,date,user:{myusername:true}}
//notice that user is a map or object and document blog has id itself wich you can use in user document and viceversa.
user:{name,lastname,blogs:{idblog1:true,idblog2:true}} //blogs is a map or object
if you want to filter by map object you can do this:
import firebase from "firebase/compat/app";
import { getFirestore } from "firebase/firestore";
const appFirebase = firebase.initializeApp(firebaseConfig);
export const dbFirebase = getFirestore(appFirebase);
const myuser= "myusername"
const q = query(collection(dbFirebase, "blogs"), where(`user.${myuser}`, "==", true));
const blogsSnapshot = await getDocs(q);
blogsSnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
console.log({blogsSnapshot});
I want to add 2 collections in Firestore in React Native.
Like JOIN can be used to add 2 tables. Is there any alternative for JOIN in Firestore to add collections?
I want to add these 2 collections users and users_2
How can I do this? Please help
At the time of writing it is not possible to query documents across collections in Firestore (it is apparently a feature that is on the roadmap however, see this recent blog post https://cloud.google.com/blog/products/databases/announcing-cloud-firestore-general-availability-and-updates -see bullet point "More features coming soon"-).
So that means that you'll have to issue two queries (one for each table, to get all the collection docs) and join/combine their results in your front end.
Another approach would be to duplicate your data (which is quite common in NoSQL world) and create a third collection that contains copies of all the documents.
For this last approach you could use a Batched Write as follows (in Javascript):
// Get a new write batch
var batch = db.batch();
var docData = {email: 'test#gmail.com', fullname: 'John Doe'}
// Set the value of doc in users collection
var usersRef = db.collection('users').doc();
batch.set(usersRef, docData);
// Set the value of doc in the allUsers collection (i.e. the third collection)
var allUsersRef = db.collection('allUsers').doc();
batch.set(allUsersRef, docData);
// Commit the batch
return batch.commit().then(function () {
// ...
});
I'm trying to setup a friend system in Firestore. My data model looks like this at the moment:
collection("users") ->
document("user1")
document("user2")
...
A document in the users collection contains data like the name, email... of the user. I'd like to enable a user to have friends now, but I'm unsure about the best way to model this.
So, I'd for sure add a friends field in the documents of the users, but what should this field contain? My first thought was a pointer to a new collection called friends in which the documents are users. Something like this:
collection("users") {
document("user1") {
name:user1,
friends: -> collection("friends") {
document("user2"),
...
}
}
}
This seems reasonable, but that'd mean that I'd have a lot of duplicate data in my database because each user that has friends will be duplicated in a friends collection. Should I worry about this or is this normal in a Firestore database structure?
Would it perhaps be possible to point to a document in the users collection from the friends collection? Something like:
collection("users") {
document("user1") {
name:user1,
friends: -> collection("friends") {
document, -----
... |
} |
}, |
document("user2")<-
}
Or should I throw away the thought of using a collection for friends and just keep a list with uids of all friends of the user?
Seems you are using two separate collections for users and friends first all you can do it by one collection. But I don't want to go there may be there was another scenario.
As your separate collection way, you can design your friends collection model to meet no duplication:
{
name : 'Name',
email : 'email#mail.com'
has_connected : {
'user1' : true // here you can use anyother unique key from user
}
}
The thing is that firestore recommend this types of design for query and for faster performance you can make that has_connected key as index.
In this approach, you have to check during adding new friend by email or any other unique key. if exists then just put another key into has_connected with the respective user. e.g user2 : true.
Finally, for fetching all friends for a user you have to do a query like this: e.g: in javascript
let ref = firebase.firestore().collection("friends");
ref
.where(`has_connected.${username}`, "==", true)
.get()
.then(//do your logic)
.catch()
Thanks