'Firebase Firestore - Get recent trending posts

How can I query for "recent trending posts" using Firestore?

I am considering it as "recent" if it is was uploaded in the last 4 hours. I am considering it as "trending" if it has more than 2000 likes.

I have tried the following:

const MIN_NUMBER_OF_LIKES_FOR_BEING_TRENDING = 2000;

async function getRecentTrendingPosts(
  limit = 10,
  minimumPostsDate = diffDate(new Date(), 4, "hours"),
) {
  const query = firestore
    .collectionGroup("userPosts")
    .where("date", ">=", minimumPostsDate)
    .where("totalLikes", ">=", MIN_NUMBER_OF_LIKES_FOR_BEING_TRENDING)
    .orderBy(date, "desc");

  const querySnapshot = await query.limit(limit).get();

  const posts = await Promise.all(
    querySnapshot.docs.map((postDoc) => parsePost(postDoc))
  );

  return posts;
}

But it doesn't work, and I am pretty sure it is because of applying ">=" to two different fields.

In a compound query, range (<, <=, >, >=) and not equals (!=, not-in) comparisons must all filter on the same field.

Any other idea for implementing this type of query?


Also, I was thinking about adding

.where("__name__", ">=", uuidv4())

to the query, just to add a degree of randomness.



Solution 1:[1]

Not the best solution, but works for me:

import _ from "lodash";

const MIN_NUMBER_OF_LIKES_FOR_BEING_TRENDING = 2000;
const MAX_TRENDING_POSTS_TO_RETRIEVE = 10;

async function getTrendingPosts(
  currentUserId
  limit = MAX_TRENDING_POSTS_TO_RETRIEVE,
) {
  const minLikes = _.random(
    MIN_NUMBER_OF_LIKES_FOR_BEING_TRENDING,
    MIN_NUMBER_OF_LIKES_FOR_BEING_TRENDING * _.random(1, 10)
  );

  const maxLikes = _.random(
    minLikes + 1, 
    (minLikes + 1) * _.random(1, 100)
  );

  const query = firestore
    .collectionGroup("userPosts")
    .where("totalLikes", ">=", minLikes)
    .where("totalLikes", "<=", maxLikes)
    .orderBy("totalLikes", "desc")
    .orderBy("date", "desc");

  const querySnapshot = await query.limit(limit).get();

  const posts = await Promise.all(
    querySnapshot.docs.map((postDoc) => parsePost(postDoc, currentUserId))
  );

  return posts;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1