Firestore order and limit data returns missing results

亡梦爱人 提交于 2020-04-16 02:55:10

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!