Firebase Multiple Databases!

Firebase allows multiple databases in the same project.

This is beneficial when you want to share authentication with between databases.

It also allows you to setup separate database rules.

My use case was to create separate databases for our suite of internal tools that have the same user base, but completely different applications, user roles, and data structures.

I just made a few tweaks to the great work done by @mark.breuss and his team.

Here is the github rebo. Please note the README is still pointing to Mark’s version and must be copied as an anvil project to be utilized.

The major differences being talked to are here:

Client Side multi-database

Where the database arguement refers to the database name in your firebase project

 initialize_app(config:dict,database=None,enable_offline_cache=False,function_region=None,persistence='local_persistence')->None:
  '''Initializes the firebase class for client side environments'''
  anvil.js.report_all_exceptions(True)

  #Check credentials input value
  if not isinstance(config,dict):
    raise ValueError('Credentials must be of type dict')

  #initialize application
  global proxy_firebase
  global app
  proxy_firebase = anvil.js.import_from("https://www.gstatic.com/firebasejs/10.4.0/firebase-app.js")
  app = anvil.js.await_promise(proxy_firebase.initializeApp(config))
  #Initialize sub modules
  authentication.init(app,persistence)
  firestore.init(app,database=database,enable_offline_cache=enable_offline_cache)
  storage.init(app)
  functions.init(app,region=function_region)

Server side Multi-database

The name argument is the same database arguement above , referencing your databse name in the firebase project.

The project_name refers to the project name in your project settings. This is important because the admin sdk does not update _database_string_internal path when changing database names. (That was a bugger to find)

def init_firebase_server(skd_config,bucket_id=None,name='default',project_name=None):
  '''Intializes the serer side firestore sdk'''
  import firebase_admin
  from firebase_admin import credentials, firestore, storage

  if bucket_id is None:
    try:
      app = firebase_admin.initialize_app(credentials.Certificate(skd_config),name=name)
    except ValueError as e:
      if "already exist" not in str(e):
        raise e
      app = firebase_admin.get_app(name=name)
    print(app.name)
    firestore_client = firestore.client(app=app)
    if name != 'default':
      firestore_client._database_string_internal = (f"projects/{project_name}/databases/{name}")
    return firestore_client
  else:
    app = firebase_admin.initialize_app(credentials.Certificate(skd_config),{'storageBucket': bucket_id},name=name)
    return firestore.client(app=app), storage.bucket()

GOTCHAS

Some gotchas I kept running into on the server side was that the firebase_admin.auth does not automatically recognize the application instance as being initialized if it is not the default database. Every time you call an auth method, you must first call the get_app() function and pass it in as an argument. See below:

  from firebase_admin import auth,get_app
  app = get_app(name=database_name)
  try:
    fire_user = auth.create_user(display_name=f'{user["name"]}',email=user['email'],app=app)
    user_id = fire_user.uid
  except Exception as e:
    if "The email address is already in use by another account." in str(e):
      return False
4 Likes