Firebase query download the whole database. Why? - firebase

I try to download and show only specific data from the Realtime Database. I have the following code:
getUserPlatformIos() {
this.dataRef = this.afDatabase.list('data/users', ref => ref.orderByChild('meta/platform').equalTo('ios'));
this.data = this.dataRef.snapshotChanges().map(changes => {
return changes.map(c => ({ key: c.payload.key, ...c.payload.val() }));
});
return this.data;
}
My firebase database structure
Firebase rules
Why firebase does download the whole database if I query before? This causes very long loading times and a lot of downloaded data....

Indexes need to be defined at the place where you the query. Since you run the query on data/users, that's where you need to define your index:
"users": {
".indexOn": "meta/platform"
}
This defines an index on users, which has the value of the meta/platform property of each user.
Note that the log output of your app should be showing an error message with precisely this information. I highly recommend checking log output whenever something doesn't work the way you expect it to work.

Related

How to create a document if the document doesn't exist or else don't do anything?

I Wanted To Ask If It Is Possible To Make A New Document With A UID If It DOESN'T Exist But if it exists NOT To Do Anything (and if possible return an error) In Firestore. (In Modular Javascript)
And If It Is Possible How?
Note: I Already Read This Question:StackOverFlow 46888701 But It Doesn't Fit My Requirements because after creating the document I want to be able to update it too.
Edit: I Wanted To Know Without Using getDoc because when i use it acts like a read and i don't want to spend lots of my no of reads from my limit.
You should first try to get the document and check if it exists then proceed to your document set/update. See sample code below:
import { doc, getDoc } from "firebase/firestore";
const docRef = doc(db, "<collection>", "<UID>");
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
console.log("Document exist!");
// Throws an error.
throw new Error('Document Exist!');
} else {
await setDoc(docRef, {
// Document Data
});
}
For more relevant information, check out these documentations:
Get a document
Update a document
Set a document
Edit:
If you don' t want to use getDoc then you have the option to use updateDoc, it will produce an error but you can still execute a setDoc method on the catch method. On this approach, you're doing a fail-safe practice that you're responding in the event of failure. See code below:
const docRef = doc(db, "<collection>", "<UID>");
// Produces error log if no document to update
updateDoc(docRef, {
// document data
})
.catch((error) => {
// console.log(error);
setDoc(docRef, {
// document data
});
});
According to the documentation, an update is just a write operation:
Charges for writes and deletes are straightforward. For writes, each set or update operation counts a single write.
We have established that an update is just a write operation (there's no reading involved). A write is a change in a document, since you're not changing anything because the document didn't exist then you won't be charged at all.
In web version 9, the function that can help you create a document is named setDoc(), which creates or overwrites a document at a specific document reference.
How to create a document if the document doesn't exist or else don't do anything?
If you want to achieve that, you have to check if the document already exists. If it doesn't exist, create it using setDoc(), otherwise, take no action, but do not use the updateDoc() function in this case.
Remember that the updateDoc() function helps only when you want to update some fields of a document without overwriting the entire document. If the document doesn't exist, the update operation will fail.
Edit:
According to your edited question, please note that there is no way you can know if a document exists, without checking it explicitly. You can indeed not do that check, but you'll end up overwriting the document over and over again. Please also note, that a write operation is more expensive than a read operation. So that's the best option that you have.

Project specific fields with Firestore? [duplicate]

Here is my data structure:
I have an ios app that is attempting to access data from Cloud Firestore. I have been successful in retrieving full documents and querying for documents. However I need to access specific fields from specific documents. How would I make a call that retrieves me just the value of one field from Firestore in swift? Any Help would be appreciated.
There is no API that fetches just a single field from a document with any of the web or mobile client SDKs. Entire documents are always fetched when you use getDocument(). This implies that there is also no way to use security rules to protect a single field in a document differently than the others.
If you are trying to minimize the amount of data that comes across the wire, you can put that lone field in its own document in a subcollection of the main doc, and you can request that one document individually.
See also this thread of discussion.
It is possible with server SDKs using methods like select(), but you would obviously need to be writing code on a backend and calling that from your client app.
This is actually quite simple and very much achievable using the built in firebase api.
let docRef = db.collection("users").document(name)
docRef.getDocument(source: .cache) { (document, error) in
if let document = document {
let property = document.get(field)
} else {
print("Document does not exist in cache")
}
}
There is actually a way, use this sample code provided by Firebase itself
let docRef = db.collection("cities").document("SF")
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let property = document.get('fieldname')
print("Document data: \(dataDescription)")
} else {
print("Document does not exist")
}
}
I guess I'm late but after some extensive research, there is a way in which we can fetch specific fields from firestore. We can use the select keyword, your query would be somthing like (I'm using a collection for a generalized approach):
const result = await firebase.database().collection('Users').select('name').get();
Where we can access the result.docs to further retrieved the returned filtered result. Thanks!
//this is code for javascript
var docRef = db.collection("users").doc("ID");
docRef.get().then(function(doc) {
if (doc.exists) {
//gives full object of user
console.log("Document data:", doc.data());
//gives specific field
var name=doc.get('name');
console.log(name);
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
});

Is it possible to go through documents in cloud firestore to see if a value of a property is equal to a comparing one?

I have website written in plain javascript to keep daily to-do tasks and the app crashed lately because different tasks of the same date was created on accident. My question is...
how can i write an if statement that checks if a document from a collection has a property (in my case the date) that is equal to the one in the input field of my form. i guess it should check after i click submit? if it exists, creation should be denyed, if not, ok to proceed.
i am using cloud firestore by the way... many thanks in advance for the help!
First, make a query to get a document that has same date:
var query = db.collection("yourCollectionName").where("date", "==", dateInInputfield);
query.get().then(function(querySnapshot) {
if (querySnapshot.empty) {
//empty
} else {
// not empty
}
});
If empty{you can proceed}, if notEmpty{some other task already exist on same date}
If you are making an app like this, a cleaner approach will be to name the id of a document as it's date, for eg. if a task is created at timestamp of 1234567, create a document named 1234567 and inside it, store all the necessary information.
By following this approach, if you create a new task, simply fetch a document by the name in inputfield,
var docRef = db.collection("yourCollectionName").doc("date");
docRef.get().then(function(doc) {
if (doc.exists) {
//this means some other document already exists
} else {
//safe to create a new document by this date.
}
}).catch(function(error) {
console.log("Error:", error);
});

cloud function trigger on create document

I need to create a firebase cloud function that will trigger every time I added a document to the collection. This the function:
exports.sendEmailConfirmation = functions.firestore.document('multies/{id}/tenties/{id}').onCreate((snap, context) => {
// Get an object representing the document
//...
return transporter.sendMail(mailOptions).catch((err) => {
console.error(err);
return {
error: err
}
});
});
I'm getting the following error in the console:
functions[sendEmailConfirmation(us-central1)]: Deployment error.
Failed to configure trigger providers/cloud.firestore/eventTypes/document.create#firestore.googleapis.com (gcf.us-central1.sendEmailApplicationConfirmation)
In the Firestore database I have a collection 'multies' that have multiple documents and foreach document I have a 'tenties' collection that could have multiple documents too. My function should trigger every time we add a document to the 'tenties' collection in any document in the 'multies' collection.
Can I get any help on how I'm configuring the path or what other error I'm having here?
I think you shouldn't have duplicated wildcards in your path:
try 'multies/{multiId}/tenties/{tentiId}' instead of 'multies/{id}/tenties/{id}'
Keep in mind that they will be available in your context.params object.

Firestore query only needed fields (Firebase) [duplicate]

Here is my data structure:
I have an ios app that is attempting to access data from Cloud Firestore. I have been successful in retrieving full documents and querying for documents. However I need to access specific fields from specific documents. How would I make a call that retrieves me just the value of one field from Firestore in swift? Any Help would be appreciated.
There is no API that fetches just a single field from a document with any of the web or mobile client SDKs. Entire documents are always fetched when you use getDocument(). This implies that there is also no way to use security rules to protect a single field in a document differently than the others.
If you are trying to minimize the amount of data that comes across the wire, you can put that lone field in its own document in a subcollection of the main doc, and you can request that one document individually.
See also this thread of discussion.
It is possible with server SDKs using methods like select(), but you would obviously need to be writing code on a backend and calling that from your client app.
This is actually quite simple and very much achievable using the built in firebase api.
let docRef = db.collection("users").document(name)
docRef.getDocument(source: .cache) { (document, error) in
if let document = document {
let property = document.get(field)
} else {
print("Document does not exist in cache")
}
}
There is actually a way, use this sample code provided by Firebase itself
let docRef = db.collection("cities").document("SF")
docRef.getDocument { (document, error) in
if let document = document, document.exists {
let property = document.get('fieldname')
print("Document data: \(dataDescription)")
} else {
print("Document does not exist")
}
}
I guess I'm late but after some extensive research, there is a way in which we can fetch specific fields from firestore. We can use the select keyword, your query would be somthing like (I'm using a collection for a generalized approach):
const result = await firebase.database().collection('Users').select('name').get();
Where we can access the result.docs to further retrieved the returned filtered result. Thanks!
//this is code for javascript
var docRef = db.collection("users").doc("ID");
docRef.get().then(function(doc) {
if (doc.exists) {
//gives full object of user
console.log("Document data:", doc.data());
//gives specific field
var name=doc.get('name');
console.log(name);
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
});

Resources