Casey West
Casey West

Reputation: 576

Firestore Subcollection '!=' query

I am aware Firestore doesn't support '!=' queries, but I was wondering if anybody has run into a similar situation as below:

Here is my db structure:

Posts -> postId -> postDocument -> likedBy -> uid

What I'm looking to do is only show posts that don't have the current user's uid in the 'likedBy' subcollection. That itself isn't possible, but I'm struggling to find even a semi-decent work around.

Currently I get all the posts and do the check locally to display the correct ones. Is this possible with perhaps a magic cloud function something?

Upvotes: 1

Views: 55

Answers (1)

Thingamajig
Thingamajig

Reputation: 4465

You might find success and use cases beyond this one by maintaining a user's feed and then only calling that at runtime. I utilize this method and have found I'm given a lot of freedom and Cloud Functions let me dictate what types of posts show and under what changes are new posts added to a user's feed.

The way I do it is I look for new posts via an onCreate cloud function and then look up who should see that post, etc. and add it to each of their feeds.

In your case I can see it being used by looking for new likes on a post. On new likes, it can remove the post from the user's feed.

An example of a function (edited for brevity) that I use to add posts to the user's follower's feeds. By grabbing using a collectionGroup query I can query the list of all users who follow the author of the post.

The schema looks like this:

Users (collection)
--- User1 (document)
------- Following (collection of people User1 is following)
----------- FollowingUser1 (document, contains a uid of "followed" user)
----------- FollowingUser2

and the Cloud Function:

exports.newReview =  functions.firestore
  .document('reviews/{reviewId}')
  .onCreate((snap, context) => {
      var reviewId = context.params.reviewId
      var reviewData = snap.data()
      var userFollowers = db.collectionGroup('following').where('uid', '==', userId)
      var followingTransaction = db.runTransaction(transaction => {
        return transaction.get(userFollowers).then(restDocs => {
          reviewData['added_via'] = 'following'
          restDocs.forEach(doc => {
            var followerId = doc.ref.parent.parent.id
            var followerRef = db.collection(`feeds/${followerId}/posts`).doc(reviewId)
            transaction.set(followerRef, reviewData);
          })
            return true
        }); 
      });

     return followingTransaction.then(values => {
          console.log(reviewData)
            var shouldPostToTwitter = reviewData.postToTwitter
            return Promise.resolve()
          }) .catch(error => {
            console.log(error)
            return Promise.reject(new Error("Error deleting"));
          });
  });

DB look something look this:

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL
});

const db = admin.firestore()

Upvotes: 1

Related Questions