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 (getIn your specific case (i.e. searching for all docs in the sameitems
, whereprovider_id
ORcompany_id
has a given value).
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: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
How to Load All Files in a Directory Using Webpack Without Require Statements
Why Do People Put Code Like "Throw 1; <Dont Be Evil>" and "For(;;);" in Front of JSON Responses
How to Achieve Dynamic Scoping in JavaScript Without Resorting to Eval
JavaScript Request Fullscreen Is Unreliable
Getting a Union of Two Arrays in JavaScript
Convert CSV Data into JSON Format Using JavaScript
Using Filesystem in Node.Js with Async/Await
What Is the JavaScript Mime Type for the Type Attribute of a Script Tag
Return Index of Greatest Value in an Array
How to Adapt Trampolines to Continuation Passing Style
How to Concatenate Regex Literals in JavaScript
Why How to Not Throw Inside a Promise.Catch Handler
Updating Svg Element Z-Index with D3
Executing Code at Page-Level from Background.Js and Returning the Value
Jquery:Select All Element with Custom Attribute
Add Commas to a Number in Jquery
Different Result for Yyyy-Mm-Dd and Yyyy/Mm/Dd in JavaScript When Passed to "New Date"
How to Replace Last Occurrence of Characters in a String Using JavaScript