44

How to get data by multiple values of one field? For example, I have a database with posts and I want to query for all posts where blogId is 1 or 2, sorting by timestamp.

collection("posts").whereEqualTo("blogId", "1")
.whereEqualTo("blogId", 2).orderBy("timestamp", Query.Direction.DESCENDING).limit(50)

The code above is not working :(

How to achieve this? Regards :)

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
Skye
  • 1,469
  • 3
  • 14
  • 25
  • This is now possible due to the Nov 7 update. Please update accepted answer: https://stackoverflow.com/a/59039919/2057171 – Albert Renshaw Nov 25 '19 at 20:52
  • Aside from the below answers, I think that this [resource](https://medium.com/firebase-tips-tricks/how-to-use-or-queries-in-firestore-6f9bc895ff83) will help. – Alex Mamo Mar 27 '23 at 12:41

12 Answers12

43

Firestore now supports "IN" queries for this purpose.

The query would look like this:

database.collection("collectionName").where("fieldName", "in", ["fieldValue1", "fieldValue2"]);

You can have up to 10 values (fieldValueX) to check "IN" of.


The code OP desired would be as follows:

database.collection("posts").where("blogId", "in", ["1", "2"]); 
Albert Renshaw
  • 17,282
  • 18
  • 107
  • 195
20

You could combine the Observables and return as one

orQuery(){

    const $one = this.afs.collection("posts", ref => ref.where("blogId","==","1")).valueChanges();
    const $two = this.afs.collection("posts", ref => ref.where("blogId","==","2")).valueChanges();

    return combineLatest($one,$two).pipe(
        map(([one, two]) => [...one, ...two])
    )
}

getOr(){
    this.orQuery().subscribe(data => console.log(data))
}
phicon
  • 3,549
  • 5
  • 32
  • 62
  • 3
    Note that final result might contain duplicates in this approach, depending on the query (in this exact scenario, there won't be duplicates sine same field is used for query with different values). – Lahiru Chandima Oct 24 '20 at 03:15
  • It may be hard if we use multi fields like your answer to paginate data. – Le Khiem Nov 11 '20 at 07:30
  • really good clear answer - many thx - a shame this is the best approach and Google can't provide a better solution – danday74 May 19 '22 at 14:53
8

Firebase has listened to our requests and they have included IN query from 7 Nov, 2019. It's a kind of OR query, where you can have upto 10 OR filters.

For android:

collection("posts").whereIn("blogId", Arrays.asList("1", "2"))
.orderBy("timestamp", Query.Direction.DESCENDING).limit(50);

Firebase documentation

hkchakladar
  • 749
  • 1
  • 7
  • 15
6

OR operator is not accepted in firebase firestore:

Cloud Firestore provides limited support for logical OR queries. The in, and array-contains-any operators support a logical OR of up to 10 equality (==) or array-contains conditions on a single field. For other cases, create a separate query for each OR condition and merge the query results in your app.

Queries in Cloud Firestore, Query limitations

Normally using firebase syntax you can call two collections:

const res1 = async collection("posts", ref => ref.where('blogId', '==', 1).get();
const res2 = async collection("posts", ref => ref.where('blogId', '==', 2).get();

and you can merge the results before serving to the view.

But in this case where you have blogIds you can use this syntax: collection("posts").orderBy('blogId').startAt(1).endAt(2);

e.d

Be Kind
  • 4,712
  • 1
  • 38
  • 45
edyrkaj
  • 169
  • 3
  • 3
5

I couldn't find any documentation for the ability to OR together where conditions. But you can rephrase your requirement on the blogId as follows:

WHERE blogId > 0 AND blogId < 3

Try this code:

collection("posts")
.where("blogId", ">", "0")
.where("blogId", "<", "3")
.orderBy("timestamp", Query.Direction.DESCENDING)
.limit(50)
Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • 4
    Yeah, but my case is little more complicated. I have an app, where user can subscribe to some blogs. So I need to retrieve all latest posts for few ids (it can be 2,5 or more ids). The ids are autogenerated (for wordpress for example - 831cacax613das) or are from blogger (for blogspot blogs - 12320183127312307212). I'm currently using firebase database with elasticsearch, but I'm interested in migrating to Firestore. – Skye Oct 13 '17 at 09:42
  • 1
    Check here for how to work with collections: https://cloud.google.com/firestore/docs/solutions/arrays – Tim Biegeleisen Oct 13 '17 at 09:45
  • Hmm, I could store blogId with single element map and query for it like in example, but in that case each blogId will require individual index for it. Currently I have 300 blogs in my database, but what if I have few thousands? :D Even if I will store it in map with integer value instead of boolean, I can query only with one field, so it's impossible to invoke this: .whereGreaterThan("blogIdMap.kqy04zya72zit5x7n9", 0) .whereGreaterThan("blogIdMap.kqy0n2dt2maqluvi3eu", 10) – Skye Oct 13 '17 at 10:02
  • Yes, this seems to be a problem. Could you join to a table which has those IDs? – Tim Biegeleisen Oct 13 '17 at 10:05
  • Nope, Currently I'm storing blogId in post entity as normal field (blogId = 123131). But, users have map of subscribed blogs (123131 = true). I'm thinking about merging query observables into one, but it's not good idea, because I want to get f.e. 10 latest posts. And I will loose pagination ability. – Skye Oct 13 '17 at 10:20
  • @Skye I gave you an upvote, which is as much as I can do. Anyway for small ranges my answer might actually be viable, so I will leave it up. – Tim Biegeleisen Oct 13 '17 at 10:21
  • @TimBiegeleisen Does this works? Because from what I read, when using range comparison, you can use orderBy only on the key you applied comparision. In this case, it is "blogId" only. So orderBy on "timestamp" will not work. Can you please confirm if it's working? – Sandip Fichadiya Dec 26 '17 at 09:56
  • @SandipSoni I can't test Firebase at the moment. – Tim Biegeleisen Dec 26 '17 at 10:02
  • @TimBiegeleisen I didn't meant that :) I meant if you remember that was working for you when you used it with Firestore. – Sandip Fichadiya Dec 26 '17 at 10:04
  • This doesn't work because the Range filter and orderBy on different fields. Source: https://firebase.google.com/docs/firestore/query-data/order-limit-data – Ari May 20 '18 at 18:19
  • Note, firebase does now support IN query which works like OR for this purpose. See here: https://stackoverflow.com/a/59039919/2057171 – Albert Renshaw Nov 25 '19 at 20:56
4

Firestore now supports OR queries (in preview) that might be useful if you want to perform an OR operation on multiple fields.. You can use it from Firebase SDK v24.4.5.

// Returns all documents with capital = true OR population > 1000000
Query query = collection.where(Filter.or(
        Filter.equalTo("capital", true),
        Filter.greaterThanOrEqualTo("population", 1000000)
));
Dharmaraj
  • 47,845
  • 8
  • 52
  • 84
3

For Android users, please note that Firestore supports now logical OR queries. So now, you can perform OR queries on multiple fields. The option is available starting with Cloud Firestore version 24.4.5.

In code, it will be as simple as:

val db = Firebase.firestore
val citiesRef = db.collection("cities")
val query = citiesRef.where(Filter.or(
        Filter.equalTo("capital", true),
        Filter.greaterThanOrEqualTo("population", 1000000)    
))

Which will return documents where the capital is set to true OR, documents where the population is greater than or equal to 1_000_000.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
2

As of March 2023, Firestore supports native or queries: https://firebase.google.com/docs/firestore/query-data/queries#or_queries

An example they give is:

const q = query(citiesRef,  
  or(where('capital', '==', true),
     where('population', '>=', 1000000)
  )
);
ErikWittern
  • 1,083
  • 9
  • 13
1

Firestore has no OR queries. They way you'd do that is by running two queries and splicing them.

You could for example:

const search = ( key, value ) =>  collection( 'users' ).where( key, '==', value ).get().then( doc => doc.data() )

Promise.all( [ search( 'name', 'John' ), search( 'name', 'Johnny' ) ] )
.then( ( [ one, two ] ) => one.concat( two ) )
.then( allResults => dothings() )
Mentor
  • 965
  • 9
  • 21
1

For Android, I am using OR query like this.

List<String> values = new ArrayList<>();
    values.add("Value 1");
    values.add("Value 2");

and then use the .whereIn query like this.

db.collection("collectionName")
            .whereIn("fieldName", values)   // where values is the list we created
            .get()
            .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                @Override
                public void onComplete(@NonNull Task<QuerySnapshot> task) {

                    if (task.isSuccessful()) {

                      // Do your stuff

                    }

                }
            });
Aamir Ali
  • 203
  • 1
  • 8
0

Try this

collection("posts").start("blogId", "1")
.end("blogId", 2).orderBy("timestamp", Query.Direction.DESCENDING).limit(50)
varun
  • 4,522
  • 33
  • 28
-1

You can use De Morgaan's laws to rewrite an AND query as an OR query.

Teymour
  • 1,832
  • 1
  • 13
  • 34