I have been reading a little about how to structure your firebase database and i understand that you need to split your data into pieces so you don't forced the client to download all of the 'users' data.
So in this example you will get all the users data when you write
ref.('users').once('value', function(snap)...
/users/uid
/users/uid/email
/users/uid/messages
/users/uid/widgets
but what if you specifically write the path to the location instead like
ref.('users/uid/email').once('value', function(snap)...
Will you still get all the users data or only the data in email ?
In firebase, you set the ref to be the reference for your database (the whole database) and then you got methods to iterate through each piece of data of your database object, hence, a good practice is to set all your database as the ref and then work from there to go through what you want to go.
// will select the whole db
const firebaseRef = firebase.database().ref();
// will select the whole app object of your db
const firebaseRef = firebase.database().ref().child('app');
// will select the whole users object of your db
const firebaseRef = firebase.database().ref().child('app/users');
So, it is a good practice to set a variable like firebaseRef to be your whole firebase db and then iterate from there.
Now, if you write:
firebaseRef.child(`users/${uid}/email`).once('value').then(snapshot => {
console.log('User email: ', snapshot.val());
}, e => {
console.log('Unable to fetch value');
});
Yes, you will get what you're asking, but you need to use the child method to get to the objects of your firebase ref.
Related
I have this Firestore onSnapshot listener on a collection (getting the entire collection). I would like to get only a subset of the the properties of each object.
Something like we do with the firebase-admin using select() on a query:
Ex: admin.firestore().collection('NAME').where(conditions).select('field1', 'field2').get()
This is the onSnapshot code: it works just fine but it's getting the full objects (containing all the properties).
const db = getFirestore();
const col = 'COL_NAME';
const q = query(collection(db, col));
onSnapshot(q, (querySnapshot) => { // How to get only a subset of fields here ?
const results = {};
querySnapshot.forEach((doc) => {
// Do something with each object
});
});
Of course I can map it on the client, but my goal is to keep data network traffic to a minimum.
How can I do it?
With the Client SDKs this is not possible.
As you have mentioned this is possible with the Admin SDK but it is also possible with the Firestore REST API: You can use a DocumentMask when fetching documents, which will "restrict a get operation on a document to a subset of its fields. ".
Note however that fetching via the REST API from a web app is much less simple than using the JS SDK. In particular the format of the response is a complex object that is not funny to parse...
Another approach would be to dernomalize your data: You create another collection which contains documents that only have the fields you want to display in the front end.
The complexity is that you need to keep the two collections in sync: when you create/modify/delete a doc in the master collection, you need to update the other collection. This can be done from your front-end (e.g. you write to the two collections in a batched write) or with a Cloud Function, triggered in the back-end with an onWrite trigger.
I'm trying to get the real-time document fields (text and timeStamp) to be displayed from the "first" collection in firestore collection, with the use of onSnapshot. I can verify that the snapshot realtime updation is working, on addition of a new document, it does shows an update. But I cannot access the text and timeStamp in the document.
onSnapshot(collection(db, 'first'), (snapshot) => {
console.log(snapshot.text, snapshot.timeStamp);
});
It just shows undefined to me. Also, I just want to access this database, db only when the user is authenticated. So is there a way to check if the user is authenticated?
To get the data from a document snapshot, you need to call data() on it. In addition, since you're reading an entire collection, you get back a query snapshot that can contain multiple documents, which you also need to handle.
So:
onSnapshot(collection(db, 'first'), (querySnapshot) => {
querySnapshot.docs.forEach((docSnapshot) => {
console.log(docSnapshot.data().text, docSnapshot.data().timeStamp);
})
});
See the documentation on getting data from Firestore and on reading all documents from a collection for more examples like this.
I have written a Firebase cloud function in which I want to get every users internal collection called 'numbers' and read each document out of that collection to do some comparisons.
Any idea how to do this?
I am pretty new to firebase and for some reason the database navigation commands are just not sticking with me very well.
I have tried a handful of commands with no success
const snapshot = functions.database.collection('users').collection('numbers').get()
let sfRef = db.collection('users');
sfRef.getCollections().then(collections => {
collections.forEach(collection => {
console.log('Found subcollection with id:', collection.id);
});
});
Here is a loose cloud code infastructure
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
export const prize1 = functions.pubsub.schedule('every 5 minutes').onRun((context) => {
const users = functions.database.ref('/users/numbers')
console.log("")
return null;
});
I feel like I have a good idea of how to do it, but the syntax is holding me back.
The collection of users. Go through each document in here, i.e. each user.
In each user go to the collection called numbers.
In the collection called numbers go through each document and find the numbers field to do logic/comparisons with.
Hopefully this can help you understand the way my database is ordered.
You could try it like this:
let usersRef = db.collection('users');
let allUsers = usersRef.get();
.then(userSnapshot => {
userSnapshot.forEach(userDoc => {
userDoc.ref.collection('numbers').get().then(numSnapshot => {
numSnapshot.forEach(numDoc => {
console.log(numDoc.data().numbers);
// here you got your numbers document with the numbers field
});
});
});
})
.catch((error) => {
console.log("Error getting document: ", error);
});
For more information you can look here and here.
You can't use functions for accessing the database. What you've defined as functions is for building triggers that respond to events. If you want to get data from Cloud Firestore, you should be using the Firebase Admin SDK via your admin instead. It might also help if you look through the official samples.
I will also point out that your code samples appear to be split between accessing Cloud Firestore and Realtime Database, which are different database products. Your screenshot shows Firestore, so ignore any APIs for Realtime Database.
I currently have the following node:
Basically what I want is to search the registry by the uid parameter. What I can not understand is that they tell me that I should not do it by means of a query, so what would be the other way? I have tried with the following:
firebase
.database()
.ref('nuevosUsuario')
.child(user.uid)
.once('value')
.then(snapshot =>
console.log(snapshot.val())
);
pero me imprime en consola null
Thank you in advance, I'm new to firebase.
You JSON structure stores user information, where it stores the information for each user under a so-called push ID (a key generated by calling push() or childByAutoId()). You're trying to query this structure to find the user based on their UID, which is stored in a property for each user. The only way to do this is by using a database query, like:
firebase.database()
.ref('nuevosUsuario')
.orderByChild("uid")
.child(user.uid)
.once('value')
.then(snapshot => {
snapshot.forEach(userSnapshot => {
console.log(snapshot.val())
});
});
You need to perform a loop here, since there may be multiple nodes that have the correct value for their UID property.
If there can logically be only one node for each user under nuevosUsuario, it is better to store the user information under the user's UID as a key, instead of using a push ID.
So you'd get a structure like:
"nuevosUsuario": {
"SYFW1u808weaGEf3fW...": {
"appellido": "PRUEBA",
"correo": "..."
...
}
}
This has a few advantages:
There can only be one child node for each user, since keys are by definition unique in a collection.
You can now get the user given their UID without a query, which is both faster and simpler in code. As in: the code in your question would work for this structure.
So I've been using Firebase as a database for my website (this is a web based project, using HTML, CSS and JS) and I'm running into a problem retrieving data from it.
Basically this site allows users to create a profile for a character (they can fill in the name, the characters stats etc...) and when they click submit, it'll save the values they filled out to the database.
The values are saved perfectly fine, but when I go to retrieve the data the command doesn't seem to do anything.
So in order to get the profiles, I've been trying to use this bit of code to get whatever is stored at the specified .ref(path):
var uid = firebase.auth().currentUser.uid;
var getChar = firebase.database().ref('/users/' + uid + '/chars/').orderByKey();
Which according to the Firebase docs should return a list of keys at the path that I specified in .ref(). However whenever I try to access whatever is in the var, it just gives me the string that contains a link to the database that looks like this:
https://#mydatabaseurlhere.firebaseio.com/users/uid/chars
Where #mydatabaseurlhere is the url I created on the Firebase app, and the uid is the authenticated user's ID.
I've been reading the docs, and its telling me that the above code should return a list of whatever is at the path that I specified, but so far it just gives me a link. Is there something I've been missing from the Docs that'll allow me to access whatever data is currently in the database? Because I've tried to take a snapshot using .once() to no avail either. I've also set the rules on /users/ to allow anyone to read/write to the database but I'm still not able to access the data (or maybe I am accessing, I'm just missing how to retrieve it).
Either way, I'm wondering how one can go about accessing this data, as I'm extremely confused as to why I can't seem to retrieve the data that has been successfully written to the database.
You're defining a query. But that doesn't yet retrieve the data.
To retrieve the data, you need to attach a listener. For example:
var uid = firebase.auth().currentUser.uid;
var getChar = firebase.database().ref('/users/' + uid + '/chars/').orderByKey();
getChar.on('value', function(snapshot) {
snapshot.forEach(function(child) {
console.log(child.key, child.val());
});
});