Search code examples
javascriptfirebasegoogle-cloud-firestoregoogle-cloud-functions

How to filter query on a nested object in Firestore


I have nested an object inside my Firestore objects and am trying to filter based on it ..but it returns no object. here is what my nested objects look like :

example of firestore database

Now in my function whenever I do something like

query = query.where('country.object_id', '==', req.query.country);

here is the function am using to get that data :


/**
 * Import function triggers from their respective submodules:
 *
 * const {onCall} = require("firebase-functions/v2/https");
 * const {onDocumentWritten} = require("firebase-functions/v2/firestore");
 *
 * See a full list of supported triggers at https://firebase.google.com/docs/functions
 */

const {onRequest} = require("firebase-functions/v2/https");
const logger = require("firebase-functions/logger");

// Create and deploy your first functions
// https://firebase.google.com/docs/functions/get-started

// exports.helloWorld = onRequest((request, response) => {
//   logger.info("Hello logs!", {structuredData: true});
//   response.send("Hello from Firebase!");
// });
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

const db = admin.firestore();

exports.getFilteredProperties = functions.https.onRequest(async (req, res) => {
    try {
        let query = db.collection('properties');

        if (req.query.country) {
            query = query.where('country.object_id', '==', req.query.country);
        }
        if (req.query.city) {
            query = query.where('city.object_id', '==', req.query.city);
        }
        if (req.query.level_1) {
            query = query.where('level_1.object_id', '==', req.query.level_1);
        }
        if (req.query.level_2) {
            query = query.where('level_2.object_id', '==', req.query.level_2);
        }
        if (req.query.level_3) {
            query = query.where('level_3.object_id', '==', req.query.level_3);
        }
        if (req.query.level_4) {
            query = query.where('level_4.object_id', '==', req.query.level_4);
        }
        if (req.query.level_5) {
            query = query.where('level_5.object_id', '==', req.query.level_5);
        }
        if (req.query.level_6) {
            query = query.where('level_6.object_id', '==', req.query.level_6);
        }
        if (req.query.level_7) {
            query = query.where('level_7.object_id', '==', req.query.level_7);
        }
        if (req.query.operationType) {
            query = query.where('type.id', '==', req.query.operationType);
        }
        if (req.query.propertyType) {
            query = query.where('propertyType.id', '==', req.query.propertyType);
        }
        if (req.query.minPrice) {
            query = query.where('price', '>=', Number(req.query.minPrice));
        }
        if (req.query.maxPrice) {
            query = query.where('price', '<=', Number(req.query.maxPrice));
        }

        const snapshot = await query.get();

        if (snapshot.empty) {
            res.status(404).send('No matching documents.');
            return;
        }

        let properties = [];
        snapshot.forEach(doc => {
            let data = doc.data();
            properties.push({
                mainImage: data.country,
                mainImage: data.mainImage,
                propertyType: data.propertyType,
                type: data.type,
                price: data.price,
                title: data.title,
                address: data.address,
                city: data.city,
                bedrooms: data.bedrooms,
                bathrooms: data.bathrooms,
                area: data.area
            });
        });

        res.status(200).json(properties);

    } catch (error) {
        console.error("Error fetching properties: ", error);
        res.status(500).send(error);
    }
});

direct filters work fine like :

query = query.where('price', '>=', Number(req.query.minPrice));

but filtering based on a nested object fails.

query = query.where('city.object_id', '==', req.query.city);


Solution

  • The syntax you're using for querying nested properties is correct, but you're passing req.query.country. Since query parameter are always a string and object_id is a number in the database, those values will never match.

    So convert req.query.country to a number (with parseInt) and pass that value into the query.