1

Following is the code I use to pull the data out from the firestore. However, as part of the development of the app, my requirement is also changed. Now, what I need is to pull the orders only for the person who is assigned to serve a particular area which can be identified with the ZIP Code which every order will have. Presently, with my code, I can get the orders based on the status of the order and by the owner of the product who posted it, which is identified with the currently logged-in user. As per my new requirement, every ZIP Code is assigned to someone (a person can be assigned to provide service to many ZIP Codes.) and I need to show users only those orders that he is assigned to provide service at. I know how to pull the data if only one ZIP is assigned to a service provider. But in this case, I have no idea how to design my database to assign ZIP codes to the service providers and to get the data.

I thought of doing it using .whereIn like I did for the 'order Status', but there are two issues, one, that there can't be two .whereIns and, two, I do not want to hard code it. So I do not know how to do it, even if my thought was right.

I hope my question is clear.

        fun getOrderStatusList(fragment: OrdersByStatusFragment) {
        mFireStore.collection("orders")
            .whereIn(
                "order_status",
                listOf("Pending", "Order Received", "In Process", "Packed", "Shipped")
            )
            .whereEqualTo("product_owner_id", getCurrentUserID())
            .get()
            .addOnSuccessListener { document ->
                val list: ArrayList<OrderStatus> = ArrayList()

                for (i in document.documents) {

                    val orderStatus = i.toObject(OrderStatus::class.java)!!
                    orderStatus.id = i.id

                    list.add(orderStatus)
                }

                fragment.successOrderStatusList(list)

            }
            .addOnFailureListener {
                fragment.hideProgressDialog()
            }
    }

EDIT:

Zip Codes that are assigned to each users are available as in the screenshot of the database. Document names are same as the id of the current user ID which is also available inside the document with the field name 'id'.

I want to get only those 'orders' that match any Zip code which is assigned to the user. Every order contain a field called zipCode.

enter image description here

Codist
  • 737
  • 8
  • 23

2 Answers2

1

If it's possible to change the database schema, I would think of something like this:

Firestore-root
  |
  --- users
  |    |
  |    --- $uid
  |         |
  |         --- zipCodes: ["zipCodeOne", "zipCodeTwo"]
  |
  --- orders
       |
       --- $orderId
              |
              --- zipCode: "zipCodeOne"
              |
              --- status: "Pending"

Since a user can provide service to more than one ZIP code, I would add an array of zip codes to each and every user. To get the orders that correspond to a user, I would perform a query for each zip code a user has:

rootRef.collection("orders")
                    .whereEqualTo("zipCode", "zipCodeOne").get()

rootRef.collection("orders")
                    .whereEqualTo("zipCode", "zipCodeTwo").get()

Each statement from above will return a Task object, so you can pass all Task objects you have to the whenAllSuccess method, like explained my answer from the following post:

Once I got the order, I can filter them on the client according to the status. However, if you need to get all the orders a user has, according to a specific status, you can also add another whereEqualTo() call like this:

rootRef.collection("orders")
                    .whereEqualTo("zipCode", "zipCodeOne")
                    .whereEqualTo("status", "Pending")
                    .get()

rootRef.collection("orders")
                    .whereEqualTo("zipCode", "zipCodeTwo")
                    .whereEqualTo("status", "Pending")
                    .get()
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Can you check my question after 'Edit' as I have updated it with new code. – Codist Jun 25 '21 at 08:06
  • Adding zip codes to a collection might incur multiple document reads. In my solution, there will always be a single document read, as you read only the User object for getting the zip codes. Besides that, most likely you aren't getting any results because I think you forgot to create an [index](https://stackoverflow.com/questions/50305328/firestore-whereequalto-orderby-and-limit1-not-working). – Alex Mamo Jun 25 '21 at 08:09
  • OK. I am not an expert in coding. I am just learning, so my questions might sound silly. I have changed the structure of my database as you said. In your code, you have used multiple `.whereEqualTo` for Zip Codes, How can that help in my case as I cannot hard code the zip code as this will keep change and there is no fixed number of zip codes for everyone. Some people serve at 3 Zips but others may serve at 7 Zipcode. Can you help me – Codist Jun 25 '21 at 09:18
  • 1
    That's the reason why I have haded that array of zip codes in the User object. You should iterate that array and get all zip codes. Once you have the zip codes add each one of them to a whereEqualTo() call. You can chain whereEqualTo() method calls as many as you want. Is it ok now? – Alex Mamo Jun 25 '21 at 09:36
  • My doubt is, we do not know how many zip codes are there for each user then how can we decide many `.whereEqualTo` should be there in the code. Why can't we use `.whereIn` instead? – Codist Jun 25 '21 at 11:02
  • 1
    There is no problem at all with the number of .whereEqualTo calls. You cannot use .whereIn because it can be used only once with a limited number of zip codes, which is 10. Is it ok now? – Alex Mamo Jun 25 '21 at 11:37
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/234195/discussion-between-codist-and-alex-mamo). – Codist Jun 25 '21 at 11:40
  • Please add as a comment. – Alex Mamo Jun 25 '21 at 12:00
  • Now I know why I cannot use .wehreIn. But, I still don't know how to write the code. How many times I should write .whereEqualTo in the code, and how to iterate and get the Zip Code. Is it possible for you to provide the code. I have tried a lot. But failed. – Codist Jun 25 '21 at 13:35
  • *ow many times I should write .whereEqualTo*, you call ` .whereEqualTo` as many times as you want. *Is it possible for you to provide the code.*, You should make your own attempt given the information in the answer and ask another question if something else comes up. *I have tried a lot. But failed.*, No worries, add a question here, on Stackoverflow, so we can take a look at it. – Alex Mamo Jun 28 '21 at 14:47
  • Sure, I will mark it as answered once it's answered. Unfortunately, I couldn't get what I wanted. My issue is not solved yet. As I said, I can change the database schema as you suggested. But I do not know how to add zip codes to Firestore as you said. I added the zip codes like "785412", "963258", "123456" from the Firestore console with the field name "zip_code" just to check if this will work, but I do not know how to read these values one by one. Could you let me know the code that I can use for both adding the zip codes as you suggested and read them? – Codist Jun 28 '21 at 20:54
  • Please edit your question and add your database structure as a screenshot with what have you tried so far. Regarding writing code, you should make your own attempt given the information in the answer and ask another question if something else comes up. – Alex Mamo Jun 29 '21 at 07:21
  • Here the main confusion, or perhaps what I do not know, is how to add the ZIP codes as an array. Because the number of zip codes will vary from user to user and what would be the field name in the Firestore. I am totally stuck due to this. – Codist Jul 02 '21 at 08:12
  • 1
    Create a POJO class, create a field of type `List`. The list will be added in a Firestore document as an array. Having that array, you can then simply [update the elements that exist within that in an array](https://firebase.google.com/docs/firestore/manage-data/add-data#update_elements_in_an_array), right? – Alex Mamo Jul 02 '21 at 08:32
  • The reason I am not accepting your response as 'Answer' because I have not achieved what I wanted. However, all your comments that I found useful has been marked as 'useful'. I know you are an expert and I could accomplish what I want but you are providing only a bit of information which is not enough for a beginner like me. That's is the reason there have been many comments and yet I couldn't get what I wanted. I am trying my best with these pieces of information but I do not get anywhere with it. Anyway, I will try your last comment. Thanks. – Codist Jul 02 '21 at 09:14
  • I have asked another question that I have been struggling with for a few days. Could you please take a look at that? Thank you. https://stackoverflow.com/q/68235402/13935956 – Codist Jul 04 '21 at 13:14
  • Finally, I have the ZIP Codes as you suggested. Could you now help me with this question? – Codist Jul 04 '21 at 13:46
  • Good to hear that made it work. Regarding the service question, I'll take a look and if I'll know the answer, I'll write it to you. – Alex Mamo Jul 04 '21 at 13:51
  • Knowing that it worked, I will ask you more to accept my answer by clicking the checkmark under the left arrows. It should change the color in green. I'd really appreciate it. Thanks – Alex Mamo Jul 04 '21 at 13:52
  • Sorry if I made any confusion here. You suggested I change the structure of my database in your very first comment. I was having trouble doing that and finally, I did it. Accordingly, I changed it and added a screenshot of it. My original question (this thread) is still not answered. Could you now look at the question where I have added the screenshot of the database and help me accomplish my task? As for accepting as the answer, I will definitely do that. Thank you. – Codist Jul 04 '21 at 16:29
  • I have provided you a solution. If you have hard times implementing it, please post a new question using its own [MCVE](https://stackoverflow.com/help/mcve), so I and other Firebase developers can help you. – Alex Mamo Jul 05 '21 at 08:28
  • If I ask a new question then that will be a duplicate question. Because the question in this thread is what I need an answer/solution for and I have not received any solution to that. In your response, you said if my database schema is changed... So I was trying to do that and that's where I had a hard time. Now that I have changed the structure of my database, could you now help me with this question? – Codist Jul 05 '21 at 09:30
  • I've asked another question which is also a part of this task. If I get an answer to that, hopefully, I could either complete my task or get close to completion. If I could accomplish my task then I can accept as the answer for both questions. I know I am getting close. Can you take a look at that? Thank you. https://stackoverflow.com/q/68235402/13935956 – Codist Jul 05 '21 at 09:30
  • Ok, I just answered your second [question](https://stackoverflow.com/questions/68235402/how-to-retrieve-data-from-firestore-that-stored-as-an-array-and-set-them-as-edit/68253986#68253986). – Alex Mamo Jul 05 '21 at 09:48
  • You said, *If I could accomplish my task then I can accept as the answer for both questions*. So I hope you consider accepting this answer as well. I'd appreciate it. Thanks – Alex Mamo Jul 06 '21 at 07:28
  • Yes, Sir. I said I will accept it as the answer once I accomplish my task which is not yet done. I marked your response on the other post as the 'accepted answer'. But no offence, I am accepting it as the answer even though my task is incomplete. But, I still hope you will help me accomplish my task. Let me try myself and I will get back with the latest update on the task, I'll post a new question if required. But earlier a similar post of mine was marked as 'duplicate' and linked back to it. Anyway, you have been a great help. By the way, the delay in response was not deliberated. Thank you. – Codist Jul 06 '21 at 10:31
  • *I'll post a new question if required.* If you are moving forward and you have hard times implementing some functionalities, please post a new question using its own [MCVE](https://stackoverflow.com/help/mcve), so I and other Firebase developers can help you. – Alex Mamo Jul 06 '21 at 11:13
  • You're very welcome and glad I could help. – Alex Mamo Jul 06 '21 at 11:13
  • I am not able to post questions, getting a message - "Wait! Some of your past questions have not been well-received, and you're in danger of being blocked from asking any more." – Codist Jul 06 '21 at 17:25
  • Hmm, I never received such a message. If you think it's some kind of bug or error, you should consider writing to the StackOverflow team. – Alex Mamo Jul 06 '21 at 17:31
  • Unfortunately, it didn't work the way you said (I think I got you right). Using multiple `.whereEqualTo`, as explained in your answer, didn't help me get what I need. I posted the question and I am still not able to get the order that matches any of the Zip Codes in the ZipList when there are more than 10 items in the ZipList. Here is my question https://stackoverflow.com/q/68275650/13935956 – Codist Jul 07 '21 at 09:01
  • As I see, you already got an answer, which I can say it's perfect for what you need, but only if you have at most 10 elements. However, I have also edited my answer. So please take a look. – Alex Mamo Jul 07 '21 at 09:40
0

Since you cannot use multiple array queries, you should consider aggregating field values or separating the field types to boolean flags. such as FieldName:true pairs.

.whereEqualTo("Order_Recieved", "true")`

You could store the ZIP code in an array, while silly, this allows you to do an array contains-any

val citiesRef = db.collection("cities")

citiesRef.whereEqualTo("pending", "true")
.whereEqualTo("orderRecieved", "true")
.whereEqualTo("inProgress", "true")
.whereEqualTo("isPacked", "true")
.whereEqualTo("shipped", "true")
Order Received.whereArrayContainsAny("postcode", listOf("05723", "36236"))

Source: https://firebase.google.com/docs/firestore/query-data/queries#in_not-in_and_array-contains-any

DIGI Byte
  • 4,225
  • 1
  • 12
  • 20
  • I am using '.whereIn' to filter the status and there can't be more than one .whereIn in query. – Codist Jun 25 '21 at 03:45
  • As I mentioned in my question that I cannot hardcode Zip Cpdes, I used another way. I have updated it in my question. Please read after 'Edit'. Thanks. – Codist Jun 25 '21 at 08:03
  • the zip codes can be dynamically populated if you have a source for it, passing them as a value would suffice - if the relationship is more direct to the user, you can assign the user.uid as a field value as well. Alternatively, if it is multi-relational, a team or area UID would suffice for a zip code if needed. I think you are on the right track – DIGI Byte Jun 25 '21 at 10:36
  • Can you check Edit 2 in my question? Thanks. – Codist Jun 25 '21 at 12:19