What is the best way to retrieve a particular field from a Firestore Document using JavaScript?

Within my Firestore database, I have a structure of users that looks like this:

https://i.sstatic.net/jgeCq.png

The rules set up for this database are as follows:

    match /users/{userID} {
      match /public {
        allow read: if request.auth != null;
      }
      match /private/{document=**} {
        allow read: if request.auth.uid == userID;
      }
    }

I am facing challenges in fetching only the public data from the user collection without retrieving everything and running into issues due to these rules. I am utilizing the Firebase Web Modular API, but it seems that the earlier version includes a .select function. However, I am unsure about its compatibility with my current code.

The latest attempt at implementing this functionality, which was auto-generated by ChatGPT and is not working properly, may seem confusing, but it represents my closest approach to solving the issue.

export const getUserFromHashedUID = async (hashedUID, fields) => {
  const db = getFirestore();
  

  // const userDocRef = doc(collection(db, 'users', hashedUID), 'public');
  const userPublicCollectionRef = collection(db, 'users', hashedUID, 'public');
  const userDocRef = doc(userPublicCollectionRef, 'public');
  
  try {
    const docSnapshot = await getDoc(userDocRef);
    
    if (docSnapshot.exists()) {
      const publicData = fields.reduce((acc, field) => {
        acc[field] = docSnapshot.get(field);
        return acc;
      }, {});

      console.log(publicData);
    } else {
      console.log('No such document!');
    }
  } catch (error) {
    console.error('Error getting document:', error);
  }

};

Answer: Upon receiving feedback, it appears that the mentioned feature is not available in the JavaScript SDK for some reason. Therefore, I'm considering restructuring my database layout as shown below to address this limitation:

users:{
  "1234567-private":{data:"data"},
  "1234567-public":{data:"data"},
  "9876543-private":{data:"data"},
  "9876543-public":{data:"data"},
}

This new arrangement provides similar efficiency to the original setup but should work seamlessly with rules and other functions (with some customization).

Answer №1

I'm having trouble figuring out how to specifically request only the public data from a collection without retrieving all of it.

Unfortunately, with the JS Client SDK, it's not possible to fetch just certain fields of a Document. Even security rules won't change this behavior.

One workaround is to split the data (public and private) into two separate documents. The most effective way would be to use two different collections and assign the same user ID in both collections for data related to the same user.

Another option is to utilize the Firestore REST API: This allows you to use a DocumentMask when fetching documents, enabling you to "restrict a get operation on a document to a subset of its fields." Keep in mind though, that someone with malicious intent could still access the documents without using the Mask if they have the collection ID.

A third solution would involve using a Callable Cloud Function to access Firestore documents. By utilizing a Cloud Function, you can control exactly what gets sent back to the front-end. You query the collection within the Cloud Function and build the response there. However, opting for a Cloud Function over a Client SDK does come with some drawbacks - check out this article for more insights.

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

What is the best way to manage Page Refresh using Angular.js?

I recently followed the tutorial at http://scotch.io/bar-talk/setting-up-a-mean-stack-single-page-application This guide went over controllers and services using angular.js for a single-page application. However, when I try to directly access /pageName o ...

Response received from the server

I am looking to display server response error messages within a form after submission. By using the following code in my JavaScript, I am able to retrieve the error message: .error(function (data, status, header, config) { $scope.postDataSuccessfully ...

Encountering a 404 error when attempting to make an Axios post request

Utilizing Axios for fetching data from my backend endpoint has been resulting in a 404 error. Oddly enough, when I manually enter the URI provided in the error message into the browser, it connects successfully and returns an empty object as expected. Her ...

Storing audio files in Firebase Cloud Database and displaying them in React js + Dealing with an infinite loop problem

Lately, I've been encountering a persistent issue that has proven to be quite challenging. Any assistance would be greatly appreciated. Thank you in advance. The objective is to create a form that allows for the easy addition of new documents to the ...

Displaying nested objects within an object using React

Behold this interesting item: const [object, setObject] = useState ({ item1: "Greetings, World!", item2: "Salutations!", }); I aim to retrieve all the children from it. I have a snippet of code here, but for some reason, i ...

Toggling javascript functionality based on media queries

On one of my slides, I want to display images that are specific to different devices like iPhone, iPad, and desktop. I am looking for a way to filter these images based on the device. Using display:none won't work as it's JavaScript, but here is ...

"Socket io Simplified: Embracing the Power of Drag

I'm currently in the process of developing a multiplayer card game using node, express, and socket io. However, I am facing some difficulties when it comes to transmitting drag and drop actions performed by one player to another connected player' ...

How can I implement a Component to show the details of a blog post when clicked in Next.js?

Can someone help me figure out how to display individual blog post details in a modal when clicked on in a blog website, where the posts are stored in a Component rather than pages? The file structure is set up like this: Component |_ Posts.js |_ PostDet ...

Is it possible to retrieve data from next.config?

I'm looking for a solution to retrieve data from a CMS within the next.config.js file. Specifically, I want to implement i18n and have the locales array dynamically fetched from the CMS instead of being hardcoded by the developer. ...

How can I adjust the number of columns displayed per page on a Bootstrap Studio website?

Currently, I am utilizing Bootstrap studio to design a website featuring multiple cards on each page. Initially, I incorporated cards from the sb-admin-2 template and everything was proceeding smoothly. In my bootstrap studio interface, the three-column ca ...

A guide on retrieving and resetting the value of a radio button within a table

I need to create multiple radio buttons within a table using Razor syntax under ASP.NET Core MVC. Each row of the table should have an update and clear link to update the record and clear the selected radio button for that specific row. <table class=&qu ...

When using AngularJS $http to send an object as a JSON key to a Spring controller, the returned value

I am attempting to transmit a json object from javascript to the Spring controller. My method of choice is using angularJs $http post for this. The issue arises when I send the key as object, with the lastName showing up as null. Strangely, if I send the s ...

AJAX: How to handle a successful POST request?

I have been recently exploring AJAX and I can see why I hesitated to delve into this particular area of JavaScript; it appears quite intricate. Most discussions seem centered around how to SEND data via POST, with little focus on what happens once the POS ...

What is the best way to conduct synchronous testing of animations in AngularJS version 1.3.15?

Encountering a migration issue with angular-animate.js while transitioning from version 1.2 to 1.3. Here is the animation code snippet: 'use strict'; angular.module('cookbook', ['ngAnimate']) .animation('.slide-down& ...

Ways to stop GCS from auto-decompressing files while working with Python SDK

I'm facing an issue with downloading a compressed object from GCS. Instead of getting the gzip file that I need, GCS automatically decompresses it for me. My goal is to download the gzip file and then decompress it locally. When I check the object me ...

Mock asynchronous calls in a React component using Jest

I am new to using jest/enzyme and I am facing a challenge in mocking a call to an asynchronous function that returns a Promise. This call is within a react component's componentDidMount method. The purpose of the test is to verify that componentDidMo ...

Using tRPC on Next.js can eliminate unawaited promises

I have a genetic variation that alters data in an external system (such as posts). Through my user interface, I publish posts on the external-api and retrieve this API to update posts after making changes. My main goal is to reflect the changes made in m ...

Error encountered with Jest: SyntaxError - React Navigation - Unexpected export token found in [node_modules eact-navigationsrc eact-navigation.js:1]

Error Encountered with Jest:- The main issue arises from react navigation. There is an error occurring in jest related to the react-navigation node_modules folder. Error at: node_modules\react-navigation\src\react-navigation.js:1 Error Det ...

In production mode, the getStaticProps function in Next.js is failing to return the expected props

I'm currently facing an issue with Next.js's getStaticProps method while trying to retrieve data from an API and display it. It works perfectly fine when I test my app locally, but once deployed on AWS Amplify for production, the data doesn' ...

Understanding the mechanics of utilizing node modules and requiring them within an Express 4 router

After initiating a node project using an express 4 generator, I have set up the following routing code in the /routes/index.js file: // ./routes/index.js var express = require('express'); var router = express.Router(); router.get('/' ...