问题
I want to do a few things when I fetch for user records in Firestore:
- filter users within an age range
- filter users based on gender, location, and favorite fruits
- get the last 6 recently joined users
- get users created before today
func observeUsers(){
let fruits: [String] = ["none"]
let location = "Paris"
let gender = "male"
let startAge = 15
let endAge = 30
let today: Double = Date().timeIntervalSince1970
var query = db.collection("users") as Query
if(!fruits.isEmpty) {
query = query.whereField("favoriteFruits", arrayContainsAny: fruits)
}
query
.whereField("location", isEqualTo: location)
.whereField("age", isGreaterThanOrEqualTo: startAge)
.whereField("age", isLessThanOrEqualTo: endAge)
.order(by: "age", descending: true)
.order(by: "created", descending: true)
.start(at: [today])
.limit(to: 6)
.getDocuments { (querySnapshot, error) in
if let err = error {
print(err.localizedDescription)
return
}
guard let docs = querySnapshot?.documents else {
return
}
docs.forEach({ (doc) in
print(doc.data())
})
}
}
I have only one composite index enabled favoriteFruits Arrays location Ascending gender Ascending age Descending created Descending
Every user has the same fields: ["gender": male, "favoriteFruits": <__NSArrayM 0x600003745590>(none), "created": 1585606054.78943, "firstname": Seven, "location": Paris, "age": 22 ]
When the query is limited to 12 all users are returned: Seven, Brian, Aaron, Chuck, Sally, Marty, Jessie, Trevor, Riley, Boren, Michael, France
When the query is limited to 6, the following users are returned in this order:
Chuck, Sally, Marty, Jessie, Riley, Boren
EXPECTED: Seven, Brian, Aaron, Chuck, Sally, Marty
the first six users to be returned
Is the problem with back pagination or indexing? Is it because I’m ordering data by two fields? Is the query cursor not unique enough?
Help is very appreciated!
Below is a screenshot of a user in Firestore:
回答1:
In the question, the fruits array is empty and that would actually cause the query to crash. So I updated the code by adding some fruits to that array with one from each user collection so they would match the query.
I populated a COLLECTION_USERS collection in Firestore with your exact data - with one exception in that the document id's were uid_0, uid_1, uid_2 but the fields are an exact match.
I then ran my updated code it it returns all three users.
Here's the updated code which is identical except for those couple of changes. (I also added in the today var as mentioned in the comments)
func querySomeData() {
var fruits: [String] = []
let location = "New York"
let gender = "male"
let startAge = 20
let endAge = 30
let today: Double = Date().timeIntervalSince1970
fruits.append(contentsOf: ["ea", "et", "id"])
let collectionUsers = self.db.collection("COLLECTION_USERS")
collectionUsers
.whereField("favoriteFruits", arrayContainsAny: fruits)
.whereField("location", isEqualTo: location)
.whereField("gender", isEqualTo: gender)
.whereField("age", isGreaterThanOrEqualTo: startAge)
.whereField("age", isLessThanOrEqualTo: endAge)
.order(by: "age", descending: true) // or ascending
.order(by: "created", descending: true)
.start(at: [today])
.limit(to: 6)
.getDocuments() { querySnapshot, error in
if let err = error {
print(err.localizedDescription)
return
}
guard let docs = querySnapshot?.documents else { return }
for doc in docs {
print(doc.documentID)
}
}
}
and the output
uid_0
uid_2
uid_1
So barring those couple of differences (adding fruits to the array and the documentID) the code in the question works.
EDIT:
The OP also wants to return users who don't have a favorite fruit, so the array in Firestore would be empty. You can't query for an empty array as a non-empty array is required for 'arrayContainsAny' filters. So the simple solution is to add a placeholder (very common in NoSQL databases) indicating the user doesn't have a favorite fruit. So the array in Firestore would look like this:
favoriteFruits
0: "none"
and the query would include this
fruits.append(contentsOf: ["ea", "et", "id", "none"])
which would return all users who have those favorite fruits, or no favorite fruits.
来源:https://stackoverflow.com/questions/60818665/firestore-order-and-limit-data-returns-missing-results