Collaborate on Firestore collection paths between administrators and web users

Seeking a solution to create reusable functions that can access Firestore Document/Collection references in both web and admin (node.js) environments.

For instance:

getUserDocumentReference(company: string, user: string) {
  return firebase.collection("companies")
    .doc(company)
    .collection("users")
    .doc(user);
}

This approach aims to minimize errors and ensure consistency across different platforms.

Challenge: While admin relies on firestore from firebase-admin, the web platform imports it from firebase.

Attempts have been made to create classes/functions where firestore reference is passed in, but dealing with return types like below becomes cumbersome:

const ref = (
    getUserDocumentReference("a", "1") as 
      firebase.firestore.DocumentReference
    )
    .withConverter(converter)

Is there a more efficient/cleaner method to achieve this without starting from scratch (maybe passing an array or reconstructing paths in a sophisticated manner)?


Approach currently employed:

class FirestoreReferences {
   constructor(firestore: firebase.firestore.Firestore
  | admin.firestore.Firestore) {
      this.firestore = firestore;
  }

  getUserDocumentReference(company: string, user: string): FirebaseFirestore.DocumentReference | firebase.firestore.DocumentReference {
     return this.firestore.collection(...).doc(...);
  }
}

Answer №1

Recently discovered Typesaurus, a platform offering universal types for seamless sharing between web and admin interfaces!

Answer №2

A recent challenge I faced involved the need to share model types between client and server Firestore. The issue stemmed from the differing Firestore types for Reference and Snapshots in firebase and firebase-admin, especially when used in different environments (browser SDK / admin SDK).

To solve this, I implemented the following steps:

  1. Creation of a separate Firestore types package: A package called @myorg/firestore-types was developed to act as a repository for Firestore types. By default, this package exports the client-side Firestore types.

  2. Utilization of the @myorg/firestore-types package in shared types and functions:

Within our shared package @myorg/firestore-models, instead of directly importing types from firebase or firebase-admin, we referenced them from our @myorg/firestore-types package.

import { Firestore, DocumentReference } from "@myorg/firestore-types";
import { User } from "@myorg/firestore-models";

// Retrieves a reference to a user document.
function getUser(
  firestore: Firestore,
  userId: string
): DocumentReference<User> {
  return firestore.doc(`users/${userId}`);
}
  1. Customization of types when necessary:

In the admin-sdk environment, TypeScript's module augmentation was employed to adapt the types in @myorg/firestore-types to align with the admin-sdk types. Here is an example:

declare module "@myorg/firestore-types" {
  export type Firestore = import("@google-cloud/firestore").Firestore;
  export type DocumentReference<T = any> =
    import("@google-cloud/firestore").DocumentReference<T>;
  export type CollectionReference<T = any> =
    import("@google-cloud/firestore").CollectionReference<T>;
  export type Query<T = any> = import("@google-cloud/firestore").Query<T>;
  export type QuerySnapshot<T = any> =
    import("@google-cloud/firestore").QuerySnapshot<T>;
  export type DocumentSnapshot<T = any> =
    import("@google-cloud/firestore").DocumentSnapshot<T>;
}

This adjustment switches the internal types utilized by our shared models to the admin-sdk versions.


This method suffices for our requirements as it solely involves References and Queries. Sharing other types may pose challenges due to potential differences in APIs between the two SDKs, making it less straightforward or even unfeasible.

Answer №3

One foolproof approach: AVOID utilizing the .doc() or the .doc().ref. Opt for the .doc.ref.path instead - a string containing the complete document path. Preserve and share it as

let refPath = whatever.doc().ref.path
and reconstruct it with .doc(refPath) in any environment.

I DON'T necessarily ADVISE this method - it reveals your internal structure - however, it's not inherently risky (assuming your security rules are intact).

By the way, I'm in the process of constructing an entire wrapper npm package (@leaddreamer/firebase-wrapper) specifically designed for this purpose.

Answer №4

Avoid using the Admin SDK for client-side tasks as it grants full control over your project, posing a security risk if accessed by unauthorized users. It is recommended to keep 'firebase' and 'firebase-admin' separate to maintain the integrity of your application.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Disable Autocomplete Chip functionality when only one can be selected

When multiple is set to true, I prefer the Chip option. Is there a way to enable the Chip functionality even when multiple is set to false? <Autocomplete className={classes.search} options={top100Films} ge ...

Launching Bootstrap 5 Modal Automatically when the Page Loads

I'm currently working on setting up an automatic modal that pops up when the page loads for a school project. I've been using Bootstrap 5, but most of the examples I found online are based on older versions. The specific modal I'm referring ...

height detection is not functioning

Here is a straightforward script that I'm using: var element = document.getElementById("container"); if (element.clientHeight == "372") { element.style.height = "328px"; element.style.marginBottom = "44px"; } else { element.style.height = "21 ...

What is the process for incorporating additional schema data into a model?

I'm currently using mongoose with MongoDB version 3.4.3 Here is my image model code: const mongoose = require("mongoose"); const CoordinateSchema = require("./coordinate"); const ImageSchema = new mongoose.Schema({ image_filename: { typ ...

What is the best way to create a dynamic information page using both V-for and V-if in Vue.js?

Hey everyone, I recently attempted to set up this layout: https://i.sstatic.net/WbcBX.png This company offers a variety of services grouped into different categories, each containing sub-options and specific details. This is how my JSON data is structur ...

How odd! Using window.location or location.replace redirects to the page and then reverses back!

While in debug mode, I am able to track which page is being accessed. Interestingly, whenever I use window.location or window.location.replace(..), the browser redirects to the specified page but then quickly returns to the original one! This strange beh ...

Secure communication and client-server API key protection

Looking for advice on building a JS app that communicates with my server using ajax. I need to give the client an api-key for authorization, but sending it through ajax poses security risks as it can easily be replicated by anyone. I don't want to req ...

You cannot modify a variable inside an event handler function unless it is declared globally in the code

I am facing an issue with my nodejs backend app that uses mongoose for database connections and queries within an event handler of socket.io. Specifically, the problem arises when I try to update a variable within a callback function of a mongoose query in ...

The effectiveness of the module is not meeting the anticipated standards

I successfully integrated a good plugin into my hapi server, and all responses are being logged. However, when I use console.log, console.error, console.warn, and console.info, the logs are only printing as plain text instead of using the good plugin forma ...

Slideshow feature stops working after one cycle

Hey there! I'm currently working on a function that allows for sliding through a series of images contained within a div. The goal is to cycle back to the beginning when reaching the end, and vice versa when going in the opposite direction. While my c ...

Combining element.scrollIntoView and scroll listener for smooth scrolling by using JavaScript

Can element.scrollIntoView and a "scroll" event listener be used simultaneously? I'm trying to create code that checks if the user has scrolled past a certain element, and if so, automatically scrolls smoothly to the next section. I attempted to achi ...

Transmit a basic JSON object from a Node.js server to an index.html webpage

People often overlook this seemingly simple solution when I search for it on Google. My goal is to send a basic json message or file to my index.html page. Here's the Node.js code: const express = require('express'); const app = express(); ...

Utilizing external functions within AngularJS Controller

I need to execute an external JS function that fetches data from a REST endpoint, which takes some time. The problem is that the graph is loading before the data is retrieved and inserted into it. External JS: function callEndpoint() { var sensorID = ...

The content of xmlhttp.responseText is not being displayed in the innerHTML

As part of my ongoing effort to enhance my understanding of Ajax for work purposes, I have been following the W3Schools tutorial and experimenting with my Apache2 server. In this process, I have placed a file named ajax_info.txt on the server (in /var/www ...

Retrieve the content of a particular text input field that is accompanied by a checkbox, and then display this information within an

In this example, the "textbox" is currently empty and requires user input. The checkbox should mirror what is typed in the textbox (type="checkbox" value=written-text-on-profile-textbox) When the checkbox is selected, it should take the text entered in th ...

JavaScript's ASYNC forEach function not following the expected sequence

I'm really struggling to understand the workings of async and await in this scenario. I want the forEach function to run before the console.log and res.json, but no matter what I do with async and await, it always ends up being the last thing executed ...

Transforming a redux form onSubmit function into a promise-based structure

One of my goals is to promisify the onSubmit handling in my submitForm for redux form. You can find a similar example here. submitForm = () => { return this.props.submituserForm() .then(() => { console.log('test') }) ...

`Incorporating JavaScript for Menu Navigation on the Homepage: Challenges Ahead`

I am attempting to modify the HTML link within the Javascript on the thank you page, but my attempts to change all respective pages' HTML links to index.html/javascript:goTo(XXXX) have been unsuccessful. How can I successfully alter the link to conne ...

How can I use Google Apps Script to generate a file using byte data?

After exploring my previous inquiry on How to reconstruct a blob for an image from a binary string (client side hidden form field) in Google Apps Script, I delved deeper and realized that my main query is about how to generate a file in Google Drive with p ...

Trouble with VueJS refresh functionality

I am facing an issue with a method that needs to run on route load. Despite attempting to call it from the updated hook, it is not functioning as expected. Additionally, I have encountered an ESLint error. methods: { getDeals (key, cb) { this.dealsR ...