0

I want to perform this query in my mobile app, >/collections{users}/{documentId}/ get some user lists who are age between 18 to 25 in Chennai location and to hide some user fields such as "lastActive" before response to client. Note, I don't want use directly to perform the action in client sdk because of security concern like to prevent rate limit, excessive requests made by users. Each response contains 10 user documents and rate limited by 20 requests per user/day. I know firestore didn't have proper way to tract user rate limit on server-side to prevent security issues. Please don't suggest to use separate subcollection to hide private fields. Simply I don't want another document read count.

Question is, I'm little bit confusing which one to choose to implement, Firestore (onCall or http) trigger function request call from firestore client SDK and another one Firestore REST API deployed it on cloud function. Note, both are deployed it on cloud function.

Seems like aren't the same? I have some requirements this functions should handle concurrent requests minimum 3000 requests.

Example code, using Firestore http trigger function.

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp();

exports.getUsers = functions.https.onRequest(async (req, res) => {
  try {
    const { minAge, maxAge, location } = req.query;
    
    // Retrieve user documents from Firestore based on age and location filters
    const usersSnapshot = await admin
      .firestore()
      .collection('users')
      .where('age', '>=', parseInt(minAge))
      .where('age', '<=', parseInt(maxAge))
      .where('location', '==', location)
      .get();
      
    const users = [];
    
    // Iterate through each user document
    usersSnapshot.forEach((userDoc) => {
      const user = userDoc.data();
      
      // Remove the "lastActive" field from the user data
      delete user.lastActive;
      
      users.push(user);
    });
    
    res.status(200).json(users);
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: 'An error occurred' });
  }
});

Another one, using Firestore REST API deployed it on cloud function

    const functions = require('firebase-functions');
const admin = require('firebase-admin');
const express = require('express');
const fetch = require('node-fetch');

admin.initializeApp();

const app = express();

app.get('/users', async (req, res) => {
  try {
    const { minAge, maxAge, location } = req.query;

    // Make a request to the Firestore REST API to retrieve user documents
    const response = await fetch(
      `https://firestore.googleapis.com/v1/projects/${process.env.GCLOUD_PROJECT}/databases/(default)/documents/users?filter=age >= ${minAge} && age <= ${maxAge} && location == '${location}'`
    );
    const data = await response.json();

    const users = [];

    // Process the response from the Firestore REST API
    data.documents.forEach((doc) => {
      const user = doc.fields;
      
      // Remove the "lastActive" field from the user data
      delete user.lastActive;

      users.push(user);
    });

    res.status(200).json(users);
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: 'An error occurred' });
  }
});

exports.getUsers = functions.https.onRequest(app);

Another one, it's similar to Firestore REST API and deployed it on cloud functions

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const express = require('express');

admin.initializeApp();

const app = express();

app.get('/users', async (req, res) => {
  try {
    const { minAge, maxAge, location } = req.query;
    
    // Retrieve user documents from Firestore based on age and location filters
    const usersSnapshot = await admin
      .firestore()
      .collection('users')
      .where('age', '>=', parseInt(minAge))
      .where('age', '<=', parseInt(maxAge))
      .where('location', '==', location)
      .get();
      
    const users = [];
    
    // Iterate through each user document
    usersSnapshot.forEach((userDoc) => {
      const user = userDoc.data();
      
      // Remove the "lastActive" field from the user data
      delete user.lastActive;
      
      users.push(user);
    });
    
    res.status(200).json(users);
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: 'An error occurred' });
  }
});

exports.getUsers = functions.https.onRequest(app);
Thangam xx
  • 17
  • 2
  • 1
    You can go with 1st approach with http trigger as that will keep implementation simple, but for your above 3000 concurrent request you could also try firebase [2nd gen](https://firebase.google.com/docs/functions/version-comparison#comparison-table) http onRequest trigger which provides up to 1000 concurrent requests per function instance. Although the requirement is not met you could scale based on number of instances and requests. – Rohit Kharche Jul 13 '23 at 12:29
  • Thank you for your valuable time to share with me. Ok I save it. Now I have one question into firestore, How to implement real-time updates on cloud functions? I know cloud functions are short lived but there is always alternate way available. Can you help me that? I said you above, i really don't want to code client-side using "onSnapshot" listener if I implement on client-side obviously I should set to security rules to allow read requests. If I write security rules to control query to allow only "onSnapshot" requests rather than get(). Can you help me with this? – Thangam xx Jul 13 '23 at 16:44
  • What about push notifications for real-time updates? I want to listen user friends list when friend is updating online status or typing status to send push notifications with newly updated data to mobile. – Thangam xx Jul 13 '23 at 17:52
  • No you cannot use onSnapshot method in firebase functions effectively because of this [answer explanation](https://stackoverflow.com/a/61310757/20239914) from Doug Stevenson. As the when you send any document from the function to the client the function automatically shuts down and does the cleaning up which contradicts the use of onSnapshot so the best option is use get() or if you want to use onSnapshot use it in client sdk – Rohit Kharche Jul 14 '23 at 06:29
  • Once again, What about push notifications for real-time updates? For example, if a user is comes to online so obviously user can update their own document field "isOnline" isn't right? In another side I have implemented onDocumentUpdated trigger function, so this could sending back to some mapping object to target user using push notifications. Don't you think is this possible? – Thangam xx Jul 14 '23 at 08:04

0 Answers0