Home > other >  Are complex compound queries possible in Firebase Firestore?
Are complex compound queries possible in Firebase Firestore?

Time:01-29

I am using Firebase as a backend for an app, and I need to create a matchmaking system where users are matched to the current user using a number of criteria.

Since the database can contain a huge amount of users, I would like to avoid retrieving every single user from the database and filtering it manually, to avoid loading times.

The relevant data stored in each user document includes: date of birth (Timestamp), an array of user interests (list of strings), an array of already matched user ids (list of strings), and the user's gender preference (string F or M).

It should find user data according to the following queries:

  1. Date of birth must be at most 2 years lower or higher than the current user
  2. The interests array must contain at least one common interest with the current user
  3. The gender must match the current user's gender preference
  4. The user id must not already be in the current user's already matched user ids list

After the list of matching users is retrieved, I would also like it to be sorted by the amount of common interests with the current user, so the best match shows first.

So far the only solution I have is to get 50 random users from the database, check if they match (in code), and if less than 6 matches are found, keep repeating until at least 6 matches are found. In case no matching users are found in the entire database, then simply get 6 random users.

I am aware of the limitations that Firebase has when it comes to querying and filtering data, so I'm asking if something like this is even possible?

CodePudding user response:

Are you using the Firestore as well with your Firebase?

There you could use queries on the firebase directly.

Query query = users.whereEqualTo("user_interest", "sports");  

Or use "in"-operator like this:

Query query = users.whereIn("user_interest", Arrays.asList("sports", "books"));

You don't have to fetch all users this way.

Checkout this link for more information: https://firebase.google.com/docs/firestore/query-data/queries?hl=en

CodePudding user response:

This type of relational data doesn't suit a NoSQL document database very well (especially when disqualifying results based on if you've seen them before), but lets ignore that for now.

Combining condition 1, 2 and 3 is possible. But you will need to disqualify results based on condition 4 on the side requesting the data (i.e. on the client/backend - Firestore's indexes can't handle it). This is because conditions 2 and 4 both rely on arrays of data and you are limited to querying against one at a time. As the number of user matches is likely to be low vs the number of users on the platform, condition 4 is better suited to code-based filtering. These limitations are well documented.

Note: Due to the sensitive nature of a user's dating profile, a profile should only contain a user's ID and profile data (no emails or phone numbers). Furthermore, you should consider serving profiles via a regulated backend such as Cloud Functions rather than just making them client-readable directly which could lead to platform abuse.

const profilesColRef = collection('profiles');

const potentialMatchesQuery = query(
  profilesColRef,
  where('dob', '>=', '1996-01-01'), // use YYYY-MM-DD format (numeric/date values can get messy with timezones if not careful)
  where('dob', '<=', '2000-01-01'),
  where('gender', '==', 'M'),
  where('interests', 'array-contains-any', userInterestArray), // supports up to 10 per query! Split into chunks of 10 and merge results for more interests
  limit(50)
);

const querySnapshot = await getDocs(potentialMatchesQuery)
const results = querySnapshot.docs
  .filter((doc) => !userPreviousMatches.includes(doc.id))
  .map((doc) => ({ id: doc.id, ...doc.data() }) // expand to basic JavaScript object

// results now contains up to 50 matches
// return results to client/use results
  •  Tags:  
  • Related