I'm trying to get changes for certain items in my list -- not all items as this is a huge list that could be modified by many people.
const ref = firebase.database()
.ref('images')
.orderByValue('place')
.equalTo('san-francisco')
ref.on('child_changed', data => {
console.log(data)
})
If I take out equalTo it works, but it will get data for every city whereas I'm only concerned about one.
Try using orderByChild instead of orderByValue
Related
Currently I have a dashboard application and when a user adds to their dashboard it does a post request to Firestore to set the data in a certain document. Here is what that code looks like:
export function createEntry(data) { // Data has a authorId key with the value of the UID
const userEntry = firestore.collection('userEntries').doc();
userEntry.set(data);
return userEntry;
}
So above, a new entry gets created with a random ID that I then use to grab the data to display later. To get this information later, I loop through all of the entries to see where the authorId matches the user that is log in to return that.
So what I am trying to do is refactor the code so that each document in 'userEntries' is the ID of the user, authorID: UID, and have it be an array where I can keep pushing items into. In return, I can just grab the user array and map over those items to display instead of looping through all my entries and checking.
What I've tried:
export function createEntry(data) {
const userEntry = firestore.collection('userEntries').doc(data.authorId);
userEntry.update({
userData: firebase.firestore.FieldValue.arrayUnion(data)
})
}
So to sum it up, I would like a way to set the document to users ID and push any future entries into their own array, in which I could easily access from the frontend to display.
Hope you can point me in the right direction, thank you!
You don't actually have to revise the original method. If you have the authorId as a field value, you can just query the data using where clause like this:
const uid = auth.currentUser.uid;
firestore.collection().where('authorId', '==', uid).get();
With this method, you are not getting the entire collection and looping through to see which one is written by the user.
I am using Firebase Realtime Database. I have an object which has all the posts created by all our users. This object is huge.
In order to display the posts in a fast way, we have given each user an object with relevant post IDs.
The structure looks like this:
/allPosts/$postID/
: { $postID: {id: $postID, details: '', title: '', timestamp: ''} }
/user/$userID/postsRelevantToThisUser/
: { $postID: {id: $postID} }
'postsRelevantToThisUser' only contains the IDs of the posts. I need to iterate over each of these IDs and retrieve the entire post information from /allPosts/
As a result, the client won't have to download the entire allPosts object and the app will be much faster.
To do this, I've written the below code. It is successfully retrieving and rendering only the relevant posts. Whenever a new postID is added or removed from /postsRelevantToThisUser/ in Firebase Realtime Database, React Native correctly re-renders the list.
However, when anything in /allPosts/$postID changes, for exampe: if title parameter changes, it is not reflected in the view.
What's a good way to solve this problem?
let userPostRef = firebase.database().ref(`/users/${uid}/postsRelevantToThisUser`)
userPostRef.on('value', (snapshot) => {
let relPostIds = [];
let posts = [];
snapshot.forEach(function(childSnapshot) {
const {id} = childSnapshot.val();
relPostIds.push(id);
})
relPostIds.map(postId => {
firebase.database().ref(`allPosts/${postId}`).on('value', (postSnapshot) => {
let post = postSnapshot.val()
posts.push(post);
this.setState({ postsToRender:posts });
})
})
Since you've spread the data that you need to show the posts to the user over multiple places, you will need to keep listeners attached to multiple places if you want to get realtime updates about that data.
So to listen for title updates, you'll need to keep a listener to each /allPosts/$postID that the user can currently see. While it can be a bit finicky in code to keep track of all those listeners, they are actually quite efficient for Firebase itself, so performance should be fine up to a few dozen listeners at least (and it seems unlikely a user will be actively reading more post titles at once).
Alternatively, you can duplicate the information that you want to show in the list view, under each user's /user/$userID/postsRelevantToThisUser nodes. That way you're duplicating more data, but won't need the additional listeners.
Either approach is fine, but I have a personal preference for the latter, as it keeps the code that reads the data (which is the most critical for scalability) simpler.
Assuming I have 1000+ blog posts. What will be the best practice to get data from firebase using axios to store in nuxtServerInit?
Can I somehow get the first 10 blog posts first during the first load and get even more data later on?
Right now I have vuex action as following:
nuxtServerInit(vuexContext, context) {
return axios
.get('https://my-blog.firebaseio.com/posts.json')
.then(res => {
const postsArray = []
for (const key in res.data) {
postsArray.push({ ...res.data[key], uid: key })
}
vuexContext.commit('setPosts', postsArray)
})
.catch(e => context.error(e))
},
You're using the REST API to access the Firebase Database. To retrieve a limited number of items, use a limit query.
https://my-blog.firebaseio.com/posts.json?limitToFirst=10
Since a limit only makes sense when you know how the items are order, you'll want to also order the items, i.e. on their key:
https://my-blog.firebaseio.com/posts.json?orderBy="$key"&limitToFirst=10
Note that the results may not be ordered, since the order of properties in a JSON object is undefined. So the result will contains the first 10 posts, but it may not show them in the right order.
Next step is to get the next 10 items. Unlike on most traditional databases, Firebase doesn't support an offset clause on its queries. So you can't tell it to skip the first 10 items to get to the next 10.
Instead Firebase queries use anchors/ranges: you must know the last item of the previous page to build the query for the next page. Say that the 10th post had a key of keyOfPost10, then you can get the next page with:
https://my-blog.firebaseio.com/posts.json?orderBy="$key"&startAt="keyOfPost10"&limitToFirst=11
We need to retrieve 11 posts here, since we're also getting the 10th post. That also means you'll need to filter the overlapping post in your client code.
I am trying to set an object in my Firebase data. While adding in database its added alphabetically sorted.
Doing something like,
const dbCon = props.db.database().ref('/pages/page');
dbCon.set({dataForFirebase});
It's setting data in the database sorted already in https://console.firebase.google.com/project/someProject/data.
How do I prevent this? Or how do get the data as the object has the order?
To fetch the data I am doing:
static async getIndividualCompoenetDetails () {
const app = await firebase.database().ref('pages/page');
const snapshot = await app.once('value');
const { dataForFirebase } = snapshot.val();
return dataForFirebase;
}
You have no control over how the database stores the data. The fact that you add the data in a certain order has no influence on how it's stored. If the order is important, store it under a key or with a property that records this order, e.g. by calling ref.push() to add new child nodes.
The Firebase console displays the data lexicographically ordered by key. This is not configurable, but sounds like a useful feature. I'd recommend filing a feature request for it, although I'll admit that I haven't heard the request frequently enough that I think it's going to be implemented.
Whenever you call snapshot.val() the data from the snapshot is converted to a JSON object, which is by definition not ordered.
This is my first app project using Google Cloud Functions & Firebase. I'm trying to find away to get a single value of the array that I'm returning and compare it to a set variable and if it matches, update another child's value in that same account.
My App users can add records to the database under their login/user_id that is stored in the database. I'm trying to get a list of the "RecordName" that is a child under that login/user_id that every user has stored in their account.
So basically every "RecordName" in the entire database. When I want to run specials for those records, I need to match the name of that record to the name of the record I have on special and if there is a match, update another child value under that user's account ("special" = true.). This way, when they load their app next time, I have it highlighting that record so they know it's on special.
When I use..
const ref = admin.database().ref(`/store`);
...with the following code...
ref.on('value', function(snapshot) {
// puts ALL items of the object into array using function ..
console.log(snapshotToArray(snapshot));
});
... and the function...
function snapshotToArray(snapshot) {
var returnArr = [];
snapshot.forEach(function(childSnapshot) {
var item = childSnapshot.val();
item.key = childSnapshot.key;
returnArr.push(item);
});
return returnArr;
};
... I get the entire array just as it is in the database:
-store
-{ones_users_id}
-recordname: value1
-special: false
-{anothers_users_id}
-recordname: value2
-special: false
ect. ect.
If my record on special is called, "Newbie Record", what would be the best way to take out every individual value for the key: "recordname" from the array, compare each one to var = "Newbie Record" and if they match, update the value of the key: "special" to be true?
I'm new to JSON and NodeJS, I've been searching on here for answers and can't find exactly what I'm looking for. Your feedback would be very helpful.
It sounds like you're looking to query your database for nodes that have "recordname": "Newbie Record" and update them.
An easy way to do this:
const ref = admin.database().ref(`/store`);
const query = ref.orderByChild("recordname").equalTo("Newbie Record");
query.once('value', function(snapshot) {
snapshot.forEach(function(child) {
child.ref.update({ special: true })
});
});
Main differences with your code:
We now use a query to read just the nodes that we want to modify.
We now use once() to read the data only once.
We loop over the children of the snapshot, since a query may result in multiple nodes.
We use the reference of each child and then update its special property.
I recommend reading a bit more about Firebase queries in the documentation.