Firestore: how to perform a query with inequality / not equals

FirebaseGoogle Cloud-Firestore

Firebase Problem Overview


I want select from Firestore collection just articles written NOT by me.
Is it really so hard?

> Every article has field "owner_uid".

Thats it:
I JUST want to write equivalent to "select * from articles where uid<>request.auth.uid"

TL;DR: solution found already: usages for languages/platforms: https://firebase.google.com/docs/firestore/query-data/queries#kotlin+ktx_5

Firebase Solutions


Solution 1 - Firebase

EDIT Sep 18 2020

The Firebase release notes suggest there are now not-in and != queries. (Proper documentation is now available.)

  • not-in finds documents where a specified field’s value is not in a specified array.
  • != finds documents where a specified field's value does not equal the specified value.

Neither query operator will match documents where the specified field is not present. Be sure the see the documentation for the syntax for your language.

ORIGINAL ANSWER

Firestore doesn't provide inequality checks. According to the documentation:

> The where() method takes three parameters: a field to filter on, a comparison operation, and a value. The comparison can be <, <=, ==, >, or >=.

Inequality operations don't scale like other operations that use an index. Firestore indexes are good for range queries. With this type of index, for an inequality query, the backend would still have to scan every document in the collection in order to come up with results, and that's extremely bad for performance when the number of documents grows large.

If you need to filter your results to remove particular items, you can still do that locally.

You also have the option of using multiple queries to exclude a distinct value. Something like this, if you want everything except 12. Query for value < 12, then query for value > 12, then merge the results in the client.

Solution 2 - Firebase

For android it should be easy implement with Task Api. Newbie example:

    FirebaseFirestore db = FirebaseFirestore.getInstance();
    Query lessQuery = db.collection("users").whereLessThan("uid", currentUid);
    Query greaterQuery = db.collection("users").whereGreaterThan("uid", currentUid);
    Task lessQuery Task = firstQuery.get();
    Task greaterQuery = secondQuery.get();

    Task combinedTask = Tasks.whenAllSuccess(lessQuery , greaterQuery)
                             .addOnSuccessListener(new OnSuccessListener<List<Object>>() {
        @Override
        public void onSuccess(List<Object> list) {

            //This is the list of "users" collection without user with currentUid
        }
    });

Also, with this you can combine any set of queries.

For web there is rxfire

Solution 3 - Firebase

This is an example of how I solved the problem in JavaScript:

let articlesToDisplay = await db
  .collection('articles')
  .get()
  .then((snapshot) => {
    let notMyArticles = snapshot.docs.filter( (article) => 
      article.data().owner_uid !== request.auth.uid
    )
    return notMyArticles
  })

It fetches all documents and uses Array.prototype.filter() to filter out the ones you don't want. This can be run server-side or client-side.

Solution 4 - Firebase

Updating the answer of Darren G, which caused "TypeError: Converting circular structure to JSON". When we perform the filter operation, the whole firebase object was added back to the array instead of just the data. We can solve this by chaining the filter method with the map method.

let articles = []
let articlesRefs = await db.collection('articles').get();

articles = articlesRefs.docs
           .filter((article) => article.data.uid !== request.auth.uid) //Get Filtered Docs
           .map((article) => article.data()); //Process Docs to Data

return articles

FYI: This is an expensive operation because you will fetching all the articles from database and then filtering them locallly.

Solution 5 - Firebase

  1. Track all user id in a single document (or two)

  2. filter unwanted id out

  3. Use "where in"


var mylistofidwherenotme =  // code to fetch the single document where you tracked all user id, then filter yourself out


database.collection("articles").where("blogId", "in", mylistofidwherenotme)

Solution 6 - Firebase

let query = docRef.where('role','>',user_role).where('role','<',user_role).get()

This is not functioning as the "not equal" operation in firestore with string values

Solution 7 - Firebase

You can filter the array of objects within the javascript code.

var data=[Object,Object,Object] // this is your object array
var newArray = data.filter(function(el) {
   return el.gender != 'Male';
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionandroid51130View Question on Stackoverflow
Solution 1 - FirebaseDoug StevensonView Answer on Stackoverflow
Solution 2 - FirebaseJurij PituljaView Answer on Stackoverflow
Solution 3 - FirebaseDarren GView Answer on Stackoverflow
Solution 4 - FirebaseAshfaq nisarView Answer on Stackoverflow
Solution 5 - FirebaseTSRView Answer on Stackoverflow
Solution 6 - FirebaseBLasanView Answer on Stackoverflow
Solution 7 - FirebaseKanishkaView Answer on Stackoverflow