Implementing or in Firestore Query - Firebase Firestore

Implementing OR in firestore query - Firebase firestore

Edit (November 2019)
Cloud Firestore now supports "IN" queries (announcement) which allows you to do a type of OR queries that look for documents with one of a few values on the same field.

For example for the query above:

db.collection('users')
.where('company_id', '==', companyId)
.where('role', 'in', ['Maker', 'Checker', 'Approver']);

Original answer

There is no "OR" query in Cloud Firestore. If you want to achieve this in a single query you will need a single field like maker_or_checker_or_approver: true.

Of course you can always do three queries and join them on the client.

OR Logical operation in Firestore Query

It currently seems that Firestore does not support disjunctions.

Workaround would be to merge results of queries query.whereEqual(name, John) and query.whereEqual(surname, James).

Keep in mind, that from the result you have to delete the duplicated ones, those which are evaluated as true in both conditions.

Firebase Firestore: Query with logical OR and pagination

I need to combine these queries (get items, where provider_id OR
company_id has a given value).

In your specific case (i.e. searching for all docs in the same items collection where provider_id or company_id equals the same value) you could denormalize your data and, for example, have an extra field provider_company_ids of type array, with two elements. The first element will hold the value of provider_id and the second element will hold the value of company_id.

Then you can use the array-contains operator as follows:

db_query = this.db.collection('items').ref
.where("provider_company_ids", "array-contains", "ABCDE");

and you'll be able to correctly paginate since it's now a single query.


Update following your comment added under your question:

After implementing the above solution, your docs will look as follows:

// Collection: 'items'
doc-id-1
provider_id: 'ABCDE'
company_id: 'FGHIJ'
provider_company_ids: ['ABCDE', 'FGHIJ'] // New field of type array

doc-id-2
provider_id: 'KLMNO'
company_id: 'ABCDE'
provider_company_ids: ['KLMNO', 'ABCDE']

doc-id-3
provider_id: 'ABCDE'
company_id: 'ABCDE'
provider_company_ids: ['ABCDE', 'ABCDE']

doc-id-4
provider_id: 'KLMNO'
company_id: 'KLMNO'
provider_company_ids: ['KLMNO', 'KLMNO']

PS: I'm not sure what is the ref property in your code (db_query = this.db.collection('items').ref.where('provider_id', '==', 'ABCDE');). I re-used it as such in my anwser, making the assumption that this.db.collection('items').ref returns a Query.

How to query Firebase Firestore with a method that works with any model

Your function doesn’t quite make sense to me, or perhaps you need to provide more context.

Instead of passing the published variable as a paramter, you need to pass a callback that returns the data fetched from Firebase.

For example:

class ShowDataViewModel: ObservableObject {

@Published var modelOneData = [ModelOne]()
@Published var modelTwoData = [ModelTwo]()
@Published var error: Error?

private var db = Firestore.firestore()

func getFromFirebase<T: Codable>(collectionName: String, callback: ([T]?) -> Void) {
db.collection(collectionName).addSnapshotListener { [weak self](querySnapshot, error) in
do {
if let error = error {
throw error
}
guard let documents = querySnapshot?.documents else {
callback(nil)
return
}
let data = try documents.compactMap { QueryDocumentSnapshot -> T? in
return try QueryDocumentSnapshot.data(as: T.self)
}
callback(data)
} catch {
self?.error = error
}
}
}

func getModelOneData() {
getFromFirebase(collectionName: "ModelOneCollection") { [weak self] (data: [ModelOne]?) in
self?.modelOneData = data ?? []
}
}

func getModelTwoData() {
getFromFirebase(collectionName: "ModelTwoCollection") { [weak self] (data: [ModelTwo]?) in
self?.modelTwoData = data ?? []
}
}

}

Then from your view you just call the functions getModelOneData() or getModelTwoData()

I’m not sure if the code will compile though, as I typed it from my iPhone.

Hope it makes sense :)

How can I create a search function for firebase firestore?

After some more creative thinking, I decided to create keywords for each document. It is not super elegant but it works. Also each "name" field is limited to X characters so I do not need to worry about the keywords field exceeding more than 20-30 individual keyword strings.

I added

var keywords: [String]?

to the StoryModel and the fields looks like this once filled in on doc creation:
keywords

And I am getting the live results with:

private lazy var storiesDataCollection = Firestore.firestore().collection("Stories")

self.storiesDataCollection
.whereField("keywords", arrayContains: self.storiesSearchText)
.limit(to: 8)
.getDocuments {}

I am not including the function that creates the keywords because I have simply not done it yet, I will edit and add it once I complete it, but for testing I just manually created the keywords in firestore. Lastly, this solution does not ignore case, the search text has to match perfectly.

EDIT: Here is the function that creates the keywords, I also added the ability to make a case matched and lowercased for better searching.

    func createKeywords(name: String) {
var keywords: [String] = []
var lowercaseKeywords: [String] = []
var alreadyKeyed: String = ""
for letter in name {
if keywords.isEmpty {
keywords.append("\(letter)")
let lower = letter.lowercased()
lowercaseKeywords.append("\(lower)")
} else {
let key = alreadyKeyed + "\(letter)"
keywords.append(key)
let lower = key.lowercased()
lowercaseKeywords.append("\(lower)")
}
alreadyKeyed.append("\(letter)")
}
let allKeywords = keywords + lowercaseKeywords
self.storiesDataCollection.document("doc id goes here").updateData([
"keywords" : allKeywords
]) { error in
if let error = error {
print("Error: \(error)")
} else {
print("SUCCESS")
}
}
}

If you were to feed it a string of "Trevor's NYE Party" here is what it would give back:

["T", "Tr", "Tre", "Trev", "Trevo", "Trevor", "Trevor\'", "Trevor\'s", "Trevor\'s ", "Trevor\'s N", "Trevor\'s NY", "Trevor\'s NYE", "Trevor\'s NYE ", "Trevor\'s NYE P", "Trevor\'s NYE Pa", "Trevor\'s NYE Par", "Trevor\'s NYE Part", "Trevor\'s NYE Party", "t", "tr", "tre", "trev", "trevo", "trevor", "trevor\'", "trevor\'s", "trevor\'s ", "trevor\'s n", "trevor\'s ny", "trevor\'s nye", "trevor\'s nye ", "trevor\'s nye p", "trevor\'s nye pa", "trevor\'s nye par", "trevor\'s nye part", "trevor\'s nye party"]

note the backslashes are not actually uploaded to firestore.

How applying logical AND (&&) in firestore query

From the docs: You can use at most one in, not-in, or array-contains-any clause per query. You can't combine these operators in the same query.



I want to get a document that has sportType Futsal and floorType Grass.

This would be the correct query:

ref.where('sportType', '==', 'Futsal')
.where('floorType', '==', 'Grass');

firestore using where and orderBy

You need to specify an orderBy for the lastChat field, as isNotEqualTo is a range condition (it helps to think of it as <> for that purpose):

var result = firestore
.collection('users')
.doc(email)
.collection("chats")
.orderBy("lastChat")
.where("lastChat", isNotEqualTo: "")
.orderBy("lastTime", descending: true)
.snapshots();

The index on lastTime is ascending, but your query is descending. That means the index doesn't match the query, and the database will return no results.

It should actually also log a warning/error with a direct link to create the index with all fields pre-populated (including the correct sort order for lastTime).



Firebase Function query and update a single Firestore document

The error message is telling you that doc.ref is undefined. There is no property ref on the object doc.

This is probably because you misunderstand the object that results from a Firestore query. Even if you are expecting a single document, a filtered query can return zero or more documents. Those documents are always represented in an object of type QuerySnapshot. That's what doc actually is - a QuerySnapshot - so you need to treat it as such.

Perhaps you should check the size of the result set before you access the docs array to see what's returned by the query. This is covered in the documentation.



Related Topics



Leave a reply



Submit