We have two different firebase projects each with its own firebase functions and realtime database used.
we have come to a situation where we want to leverage one of the dataset (a node in the realtime db) from project 1 into the project 2.
As this node is read-only true so i can a access it in the format
https://myproject.firebaseio.com/prj1db/nodeX.json
but that will give entire data for this node. What i need is to query specific data like i do using below format for the db attached to the same project in the firebase function:
const rsp = await db.ref("/users/").orderByChild("color").equalTo("pink).once("value")
is there a way?
So above answer did not work even being super close to what i need. The above response ends up giving error indicating there is a security issue.
What worked for me was that i used the service key approach with below code
const scanbuddyDBApp = admin.initializeApp({
credential: admin.credential.cert("./src/scanbuddy_service_key.json"),
databaseURL: "https://mydb.firebaseio.com",
}, 'scanbuddy');
Related
I am trying to migrate from Firebase Real time Database to Cloud Firestore in order to use "complex" queries among collections but I found some "issues" that I don't know how to solve.
My server uses Express JS and Firebase Admin SDK. I am trying to create a CRUD router for my admin dashboard but I am getting the following error:
"9 FAILED_PRECONDITION: The query requires an index. You can create it here: ...
When I access that URL (...) I get some error I don't have enough permissions... Well, anyway, after some research I understood that "complex" queries requires indexes and they have to be more than one.
This is my current router code so you can see what I want to achieve:
// GET - Get users
router.get('/', async (req: Request, res: Response) => {
...
let ref: any = db.collection('users').orderBy('createdAt');
Object.keys(req.query).forEach(key => {
ref = ref.where(key, '==', req.query[key]);
});
...
});
As you can see when I iterate req.query key I am adding a conditional statement to the query. My idea is to progamatically add custom filters from the client.
According to what I understood from documentation, I should create a complex index type for every document property.
Therefore, what should I do in order to achieve the mentioned idea? Thanks in advance.
Firestore compound queries have some limitations.
One is that to use more than one method, for example "where" and "orderBy", you need to create an index for this query.
So in your case, as your queries are dynamic, for each query you will have to create an index.
My suggestion is that you only use the "where" in your queries and in the other filters use javascript to filter. Or migrate to another database like MongoDB.
This is the link to the Firestore documentation explaining the compound queries: https://firebase.google.com/docs/firestore/query-data/queries?hl=en-us
I am creating a multiplayer game website. I am using three features of firebase.
Firebase authentication
Firestore
Real time database
The data which is permanent is stored in firestore. Like profile image, username etc. The data in firestore is stored in collection users and the key is same as the authentication id which we get from user.uid
The second data is temporary data which contains the chat messages and current game situation and player turn etc. This data is stored in real time database.
There are two base objects in real time data base. One is rooms and other is users. When a user logs in to website the permanent data is taken from the firestore and placed with temporary data(because we might need to display the permanent data again and again). The function I am using to get permanent data and create combination with temp data is
//'uid' is the permanent id which is used in firestore and also in authentication.
export const addUser = async (uid: string) => {
//gets the permanent data from firestore
const data = await getUserData(uid);
//Set it to realtime database my adding one more temp prop
return await dbUsers.child(uid).set({...data, messages: []});
};
Till now everything is fine problem comes when I have to remove the user on disconnection. I used t
export const removeUser = async (uid: string) => {
return await dbUsers.child(uid).remove();
};
The above way doesn't work for multiple tabs. Consider if user had opened multiple tabs and he just closed one server then realtime database will consider it logged out.
Do I need to create realtime data on the basis of another id using push() method. Kindly guide me to correct path.
If I understand correctly you're trying to track the user's online status using Firebase's onDisconnect handlers. To do this:
You write a value for the user's UID when they connect.
You then delete that value using an onDisconnect handler.
This indeed will not work when the user opens the app in multiple locations (tabs, browsers, or devices). The reason is that a user can be online in multiple locations, and your code and data structure needs to cater for this.
The idiomatic approach is the one outlined in the sample presence app in the Firebase documentation, and works with a data structure like this:
"OnlineUsers": {
"uidOfUser1": {
"-LKeyOfConnection1": true,
"-LKeyOfConnection2": true
},
"uidOfUser2": {
"-LKeyOfConnection3": true,
"-LKeyOfConnection4": true
}
}
In this structure, if a user has two open connections (on different tabs, browsers, devices), they have two nodes under their UID, each with its own onDisconnect handler. When both connections are closed, with connection keys disappear, and thus their /OnlineUsers/$uid node also disappears automatically.
So to detect if a user is online in the above structure, you'd check if there is a node under /OnlineUsers with their UID.
I would like a Google Cloud project A (project-a-id) to access the firestore data of another Google Cloud project B (project-b-id). For the same I added project A default service account viz. project-a-id#appspot.gserviceaccount.com in the IAM of project B and set the role to Cloud Filestore Editor.
In the cloud function of project A, I am trying to access both project A's (its own) firestore as well as project B's firestore but it keeps showing project A default database for both Apps. The code is:
var primaryAppConfig = {
databaseURL: 'https://project-a-id.firebaseio.com'
};
var primaryApp = admin.initializeApp(primaryAppConfig, 'primary');
var primarydb = admin.firestore(primaryApp);
var secondaryAppConfig = {
databaseURL: 'https://project-b-id.firebaseio.com'
};
var secondaryApp = admin.initializeApp(secondaryAppConfig, 'secondary');
var secondarydb = admin.firestore(secondaryApp);
I was under the impression if the default service account of project-a is given rights in project-b it should automatically get rights. At least I found it applicable when I am accessing google cloud storage buckets in this manner.
Is something else to be done? Thanks
I have a cloud-native firestore as opposed to a real-time database in project-a. However, was facing the same issue when I tried to access it from project-b.
Was able to solve it by generating a service account with access to project-a firestore, downloading the credentials and accessing the same from project-b with the following:
credential_path = "pathTo/xxxxx.json"
db = firestore.Client.from_service_account_json(credential_path)
You need to create apps within current firebase project.
Firebase Console -> Project Setting -> General -> Add App
These apps will have access to same firestore but will be deployed seperately under different subdomains(under firebaseapp.com).
I'm trying to do server side rendering with Firebase and am struggling with using the Admin SDK to impersonate a uid so that all database security rules are followed as if the request came from an authenticated user with the same uid. I'm aware of the databaseAuthVariableOverride functionality in initializeApp, but that only works for a single initialization, not a potentially enormous amount per second. Anyone have a totally different approach or suggestions for me?
Here's the equivalent of what I would like to do:
const getAdminAsUser = (authorizedUid) => firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(adminConfig),
databaseURL: firebaseConfig.databaseURL,
databaseAuthVariableOverride: {
uid: authorizedUid,
},
});
Let me explain the situation (excuse my english, I will do my best):
I have two Firebase Web projects in my Firebase console: coretechtest-ce207 and agon-plugin
coretechtest-ce207 is the main app and agon-plugin is a secondary app wich needs to connect to the auth and database of coretechtest-ce207. As far as I know I can't host two apps on the same project so thats why I made to separated projects. The main one works fine, I can do everything I want (signup, database, etc.) but I need the main and the second one both on the same auth and DB. agon-plugin (secondary one) is made based on the FriendlyChat app and connects directly to the server in wich the app is hosted.
For example:
// Initializes FriendlyChat.
function FriendlyChat() {
this.initFirebase();
}
// Sets up shortcuts to Firebase features and initiate firebase auth.
FriendlyChat.prototype.initFirebase = async function() {
// Shortcuts to Firebase SDK features.
this.auth = firebase.auth();
this.database = firebase.database();
this.storage = firebase.storage();
// Initiates Firebase auth and listen to auth state changes.
await this.auth.onAuthStateChanged(this.onAuthStateChanged.bind(this));
};
As you can see there is no need to put
apiKey: "AIzaSyAfGm_ILVdfsd--Fw7aascc8tAB73q__Bbko",
authDomain: "coretechtest-ce207.firebaseapp.com",
databaseURL: "https://coretechtest-ce207.firebaseio.com",
projectId: "coretechtest-ce207",
storageBucket: "coretechtest-ce207.appspot.com",
messagingSenderId: "994718782"
I tryied replacing it using those parameters so it would be
FriendlyChat.prototype.initFirebase = async function() {
// Shortcuts to Firebase SDK features.
this.auth = 'coretechtest-ce207.firebaseapp.com';
this.database = 'https://coretechtest-ce207.firebaseio.com';
this.storage = 'coretechtest-ce207.appspot.com';
// Initiates Firebase auth and listen to auth state changes.
await this.auth.onAuthStateChanged(this.onAuthStateChanged.bind(this));
};
But no luck there, can you tell me what I am doing wrong? I thought that replacing that would connect to my main project but it did not... =/
I hope you can understand what Im trying to say!
Thanks!
Not 100% sure about Web, but it should be similar to Android :
Going to your console panel
On top left click on the wheel next to "Project OverView"
In the pop-up click on Project Setting
In the settings page scroll down a little bit and you should see a blue "add app" (or something like that) button.
Then do everything you did on your first app to your second app
Most importantly, dont post your api key on the web !
If you're using Web and want to host 2 webapps that use the same database - you have a couple options.
Free: the only thing that associates a web app to your db is the api keys in the Firebase config used to initialize firebase in the web app. If 2 apps use those same settings then they can share the same db. If you are wanting to host both web apps with firebase for free - only 1 app can be hosted for free per project. However, you can easily create a 2nd new project and host your 2nd web app in that new project. But don't use the new web api settings from that new project inside your app. Instead use the same ones from your original project. 2 apps in 2 projects can use the same DB if they use the same API keys config. (only select firebase hosting when doing 'firebase init' from the cli for the 2nd app)
A paid option: is if you go to the Hosting page in your firebase console, and you scroll down to the bottom -you will see a card offering hosting more than 1 app in 1 project. It requires you to update to the pay-as-you-go blaze plan. Which may or may not cost you money.