How many times should I call firebase.analytics()? - javascript

When using Firestore, I see people using this pattern:
export const db = firebase.firestore();
And then use the db reference across the app to access the Firestore interface.
But I don't usually do this. I prefer to use it like:
firebase.firestore().collection("myCollection").get() // I USE IT LIKE THIS ACROSS THE APP
Whenever I need Firestore, I always call firebase.firestore()
Basically I'm getting the same reference over and over again to the Cloud Firestore service interface.
And it works just fine.
QUESTION
Can the same concept be applied to the firebase.analytics() call?
I.e: can I call it multiple times throughout my app (like the Firestore example) or will I be logging the same default events over and over again on each call?
Like: calling firebase.analytics() everytime I need the Analytics interface.
Because I know that just by calling it once, you're already logging (sending) out some default events.
Would it make any difference to use it like this:
export const analytics = firebase.analytics();
And then use the analytics to log events, instead of firebase.analytics().logEvent() everytime ?

firebase.analytics() just returns a singleton object, the same every time. All of the Firebase product entrypoints exposed by the firebase object are all that way. Whatever method you want to use to get that singleton object is completely up to you.

Related

How to use the Firebase objects in different files?

This might be a stupid question but I am learning all of this by myself and I didn't find anything about it in the documentation.
I am currently building a Vue app and using Firebase as my backend. In order to use the Firebase services, you create an app object with the initializeApp() method and then access services like the database by calling getDatabase(app) and working with the returned object. Now my question is: If I do these things inside my top level component (App), but then need to access the database inside another component, can I just call the getDatabase() method again, or do I have to somehow export the first object so that I can access it from other files?
The Firebase SDKs are pretty good at re-using objects behind the scenes, so you can typically call initializeApp once and then call getDatabase in each component.

Vuejs - Get different date in the same component

I have created several components (tables, selects, etc) and all use the same methods to get API information.
The purpose is to use these components on different pages of the application and as such, so that one can use the same component (eg table) regardless of the information it receives, I have created a number of methods to allow this.
However, to apply these methods to all components requesting the API, you would have to repeat a lot of code, and as such the goal is to create these methods globally.
After a search I found three ways to do it, with Plugins, Mixins and Vuex. However I do not know what is the most ideal way to do this.
Any suggestion?
Go with Vuex.
Create a centralized store where your components interact with its data using getters, actions and mutations, and the store knows how to interact with the API.
For example, your table component can be dumb, and just expect a :data=someData that the component that initializes the table passes to it, then it just renders whatever was passed. This someData can be mapped to a Vuex getter (or directly to an item in the store state) in the parent component.
When your component needs to have something submitted to the API, it can trigger an event the parent will pick up and call the appropriate action or mutation on the store, the store will know what to call in the API to do this action. So, even your parent isn't completely aware on how the API works, just your abstraction of if, represented by your Vuex store.
I have created a very simple todos application last week for another question here, feel free to have a look, uses Vue, Vuex and saves the data to Firebase. It also doesn't implement REST as it could, but it isn't too hard to change the store to use the proper REST methods get, post, put, delete etc.
All the relevant code of this application in in App.vue and store.js, with one line in main.js just to add the store to the Vue instance.
Vuex will help with shared/own components state. If your problem is how to manage shared API call Vuex persi won't tackle that problem directly. It will help you once you get that data accessible to your components.
That said, you can create a module to do the API call and retrieve data, say:
http.js
export const getUser = async id => {
const response = await fetch(`/user/${id}`)
return await response.json()
}
export const getContent = async id => {
const response = await fetch(`/content/${id}`)
return await response.json()
}
This is a solution that will help you both with or without Vuex, now you can call those methods from anywhere.

Angular 4 async data storage

I'm creating a testing application that has 1000s of questions hosted on firebase. To prevent downloading the questions multiple times, I've implemented a questions service where in the constructor I download the questions:
this.db.list("questions/", { preserveSnapshot: true}).subscribe(snapshots => {...}
This downloads the questions and pushes them to a questions array so that I don't have to re download until the next session. I also have a function to serve the questions:
getQuestion(){
return this.questions[0];
}
However, because of the asynchronous nature of firebase, often times the data is not yet downloaded before getQuestion() is called, so it returns undefined.
Is there a proper way to implement this data store type pattern in angular, and make sure the async call in the constructor finishes before getQuestion() gets called?
I've tried adding a variable ready, initializing it to false, and setting it to true when the async call returns. Then, getQuestions() is modified to look like:
getQuestion(){
while(!this.ready()){}
return this.questions[0];
}
However this just causes the app to hang.
It's almost never necessary to use preserveSnapshot. Not having to worry about snapshots is one of the main benefits of using AngularFire. Just write this.db.list(PATH).subscribe(list =>.
You're confusing "downloading" with "subscribing". It is hardly ever a good idea to subscribe inside a service, and store the data locally--you'll never be exactly sure when the subscribe handler has run, as you have found.
Instead, the service should provide an observable, which consumers--usually components-will consume. Those consumers can subscribe to the observable and do whatever they want, include storing the data statically, or, preferably, you can subscribe to the observable directly within a template using the async pipe.
The general rule is to subscribe as late as possible--ideally in the template. Write your code as a set of observables which you map and filter and compose.
Firebase caches results and in general you don't need to worry about caching yourself.
Call getQuestion() function after Data from FireBase was downloaded.
Use blow code:
this.db.list("questions/").subscribe(list => {...} //etc

How do Meteor.subscribe and MyCollection.find* operations interact?

I've been following lots of meteor examples and working through discover meteor, and now I'm left with lots of questions. I understand subscribe and fetch are ways to get "reactivity" to work properly, but I still feel unsure about the relationship between find operations and subscriptions/fetch. I'll try to ask some questions in order to probe for some holistic/conceptual answers.
Question Set 1:
In the following example we are fetching 1 object and we are subscribing to changes on it:
Meteor.subscribe('mycollection', someID);
Mycollection.findOne(someID);
Does order of operations matter here?
When does this subscription "expire"?
Question Set 2:
In some cases we want to foreign key lookup and use fetch like this:
MyCollection2.find({myCollection1Id: doc1Id}).fetch();
Do we need also need a MyColletion2.subscribe when using fetch?
How does subscribe work with "foreign keys"?
Is fetch ~= to a subscription?
Question Set 3:
What is an appropriate use of Tracker.autorun?
Why/when should I use it instead of subscribe or fetch?
what happens when you subscribe and find/fetch
The client calls subscribe which informs the server that the client wants to see a particular set of documents.
The server accepts or rejects the subscription request and publishes the matching set of documents.
Sometime later (after network delay) the documents arrive on the client. They are stored in a database in the browser called minimongo.
A subsequent fetch/find on the collection in which the aforementioned documents are stored will query minimongo (not the server).
If the subscribed document set changes, the server will publish a new copy to the client.
Recommended reading: understanding meteor publications and subscriptions.
question 1
The order matters. You can't see documents that you haven't subscribed for (assuming autopublish is off). However, as I point out in common mistakes, subscriptions don't block. So a subscription followed by an immediate fetch is should return undefined.
Subscriptions don't stop on their own. Here's the breakdown:
A global subscription (one made outside of your router or template) will never stop until you call its stop method.
A route subscription (iron router) will stop when the route changes (with a few caveats).
A template subscription will stop when the template is destroyed.
question 2
This should be mostly explained by the first section of my answer. You'll need both sets of documents in order to join them on the client. You may publish both sets at once from the server, or individually - this is a complex topic and depends on your use case.
question 3
These two are somewhat orthogonal. An autorun is a way for you to create a reactive computation (a function which runs whenever its reactive variables change) - see the section on reactivity from the docs. A find/fetch or a subscribe could happen inside of an autorun depending on your use case. This probably will become more clear once you learn more about how meteor works.
Essentially, when you subscribe to a dataset, it fills minimongo with that data, which is stored in the window's local storage. This is what populates the client's instance of that Mongo with data, otherwise, basically all queries will return undefined data or empty lists.
To summarize: Subscribe and Publish are used to give different data to different users. The most common example would be giving different data based on roles. Say, for instance, you have a web application where you can see a "public" and a "friend" profile.
Meteor.publish('user_profile', function (userId) {
if (Roles.userIsInRole(this.userId, 'can-view', userId)) {
return Meteor.users.find(userId, {
fields: {
public: 1,
profile: 1,
friends: 1,
interests: 1
}
});
} else {
return Meteor.users.find(userId, {
fields: { public: 1 }
});
}
});
Now if you logged in as a user who was not friends with this user, and did Meteor.subscribe('user_profile', 'theidofuser'), and did Meteor.users.findOne(), you would only see their public profile. If you added yourself to the can-view role of the user group, you would be able to see public, profile, friends, and interests. It's essentially for security.
Knowing that, here's how the answers to your questions breaks down:
Order of operations matters, in the sense that you will get undefined unless it's in a reactive block (like Tracker.autorun or Template.helpers).
you still need to use the subscribe when using fetch. All fetch really does is return an array instead of a cursor. To publish with foreign keys is a pretty advanced problem at times, I recommend using reywood:publish-composite, which handles the annoying details for you
Tracker.autorun watches reactive variables within the block and will rerun the function when one of them changes. You don't really ever use it instead of subscribing, you just use it to watch the variables in your scope.

Firebase child() vs. Angularfire $firebaseObject

I am trying to understand WHEN Firebase actually loads the data to the client vs. doing "lazy load" (only download the data when it's needed). The reason is that I am saving images (base64) in Firebase (please don't ask why as it's only few hundred MBs). So there are two choices:
// With typical Firebase
var imagesRef = Ref.child('images');
// With Angularfire
var imagesObj = $firebaseObject(Ref.child('images'));
Ref is just a reference to my Firebase URL.
I know with Angularfire, there is $loaded() which makes me think Angularfire actually loads all the data AT ONCE and makes it available when you call $firebaseObject() right away. Is it correct?
As for using child(), I don't see any load() event to catch based on the documentation. Maybe I missed it. But does it load all data from the server to client?
If I have like 500MB of images, I definitely don't want this load-all-at-once happening.
firebase retrieve the data when you call .on on a ref
As not widely know, all the data are retrieved in one piece (wether you call .on 'value' or .on 'child_added'), so you better paginate your result using orderByFirst / Last, or using firebase util
What angular fire does when you instanciate a firebaseObject / array is calling on 'value' / 'child_added' from within the constructor function of the instance, so yes , the data are retrieved almost instantly (but in a defer hence the $loaded() function).
Check out the source code of the Object manager and the constructor of $firebaseObject for instance, it's pretty clear

Categories