【问题标题】:How to get data from Firebase that match two criteria where one criteria is an array?如何从 Firebase 获取符合两个条件的数据,其中一个条件是数组?
【发布时间】:2021-07-06 18:22:51
【问题描述】:

我正在使用以下代码从Firestore 获取一组数据,这是一组邮政编码(从名为“用户”的集合中检索)。然后,我想从另一个集合(称为“订单”)中获取与数组中的任何邮政编码匹配的数据,以及与待处理、打包、处理中匹配的“订单状态”。

        fun getZipCodesFromFirebase(fragment: OrdersByStatusFragment) {

    val uid = FirebaseAuth.getInstance().currentUser!!.uid
    val rootRef = FirebaseFirestore.getInstance()
    val followingRef = rootRef.collection("users")
    val uidRef = followingRef.document(uid)
    uidRef.get().addOnCompleteListener { task ->
        if (task.isSuccessful) {
            val document = task.result
            if (document.exists()) {
                val zipCodes = document.toObject(User::class.java)?.zip_codes
                Log.d("Zip Codes", zipCodes.toString())
                
                getOrderStatusList(fragment, zipCodes)

            } else {
                Log.d("TAG", "No such document")
            }
        } else {
            Log.d("TAG", "get failed with ", task.exception)
        }
    }

}

然后我尝试使用以下代码来获取具有上述订单状态的订单以及与任何邮政编码匹配的订单。但我无法正确理解。

    fun getOrderStatusList(fragment: OrdersByStatusFragment, zipList: List<String>?) {

    mFireStore.collection("orders")
        .whereEqualTo("address.zipCode", zipList?.get(0))
        .whereEqualTo("address.zipCode", zipList?.get(1))
        .whereEqualTo("address.zipCode", zipList?.get(2))
        .whereEqualTo("address.zipCode", zipList?.get(3))
        .whereEqualTo("address.zipCode", zipList?.get(4))
        .whereEqualTo("address.zipCode", zipList?.get(5))
        .whereEqualTo("address.zipCode", zipList?.get(6))
        .whereEqualTo("address.zipCode", zipList?.get(7))
        .whereEqualTo("address.zipCode", zipList?.get(8))
        .whereEqualTo("address.zipCode", zipList?.get(9))
        .get()
        .addOnSuccessListener { document ->
            val list: ArrayList<OrderStatus> = ArrayList()

            for (i in document.documents) {

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

                if (orderStatus.order_status == "Pending" || orderStatus.order_status == "Packed" || orderStatus.order_status == "In Process"
                    || orderStatus.order_status == "Order Received") {
                    list.add(orderStatus)
                }

            }
            Log.d("Zip Code", list.toString())
            fragment.successOrderStatusList(list)

        }
        .addOnFailureListener {
            fragment.hideProgressDialog()
        }
}

简而言之,我想要与邮政编码和订单状态匹配的订单。其中 Zip codes 是从另一个名为 users 的数组中检索到的,并且订单状态是硬编码的。

数据库结构如下图所示。

使用字段“zip_codes”收集“用户”。

包含字段“order_status”和“zip_codes”的集合“订单”

我希望我的问题足够清楚。

谢谢。

编辑:>>最新的工作代码。

    fun getOrderStatusList(fragment: OrdersByStatusFragment, zipList: List<String>?) {

    mFireStore.collection("orders")
        .whereIn("address.zipCode", zipList!!)
        .get()
        .addOnSuccessListener { document ->
            val list: ArrayList<OrderStatus> = ArrayList()

            for (i in document.documents) {

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

                if (orderStatus.order_status == "Pending" || orderStatus.order_status == "Packed" || orderStatus.order_status == "In Process"
                    || orderStatus.order_status == "Order Received"
                ) {
                    list.add(orderStatus)
                }

            }
            Log.d("Zip Code", list.toString())
            fragment.successOrderStatusList(list)

        }
        .addOnFailureListener {
            fragment.hideProgressDialog()
        }
}

【问题讨论】:

    标签: kotlin google-cloud-firestore


    【解决方案1】:

    这个结构:

    mFireStore.collection("orders")
        .whereEqualTo("address.zipCode", zipList?.get(0))
        .whereEqualTo("address.zipCode", zipList?.get(1))
        .whereEqualTo("address.zipCode", zipList?.get(2))
        .whereEqualTo("address.zipCode", zipList?.get(3))
        .whereEqualTo("address.zipCode", zipList?.get(4))
    

    过滤结果以仅包含顶级address字段的zipCode属性等于zipList?.get(0)等于zipList?.get(1) 等于zipList?.get(2) 等。由于没有单个字段可以等于多个值,因此不返回任何内容。

    您更有可能正在寻找array-contains-any condition,它看起来像这样:

    citiesRef.whereArrayContainsAny("zipCode", zipList!)
    

    与过滤order_status 类似,您可以使用同一文档中的in 条件:

    citiesRef
      .whereIn("order_status", listOf("Pending", "Packed", "In Process"))
    

    不幸的是,您不能将这两个条件结合起来,如文档所述:

    每个查询最多可以使用一个innot-inarray-contains-any 子句。您不能在同一个查询中组合这些运算符。

    因此,您必须在查询中执行其中一个条件,然后在您的应用程序代码中过滤另一个条件。

    【讨论】:

    • 我尝试了mFireStore.collection("orders") .whereArrayContainsAny("address.zipCode",zipList!!),但它什么也没返回。当我使用mFireStore.collection("orders") .whereEqualTo("address.zipCode", zipList?.get(0)) 时,我得到了预期的结果。但我可以从一个位置检查价值。 zipList?.get(0))。如果我从数组中的下一个位置添加值,它不会返回任何内容,正如您在回复中解释的那样。 .whereArrayContainsAny 不应该工作吗?
    • 您的第二张截图看起来与第一张大不相同。要查找该邮政编码与列表中的值之一匹配的文档,应为:.whereIn("address.zipCode", zipList!!)
    • 谢谢你,成功了。我已经更新了问题中的最新代码。你能看一下,然后告诉我是否可以或需要任何改进吗?我使用if 语句按“订单状态”过滤掉。我怀疑如果 zipList 包含超过 10 个项目,这是否仍然有效。
    • 文档非常清楚,项目数的限制是 10。之后,您必须为每 10 个项目触发一个单独的查询,或者找到另一种方式来执行查询。如果这些都不适合您,请考虑 Firestore 是否适合您/您的项目。
    猜你喜欢
    • 1970-01-01
    • 2022-06-14
    • 1970-01-01
    • 1970-01-01
    • 2011-04-27
    • 2014-02-18
    • 1970-01-01
    • 1970-01-01
    • 2013-09-10
    相关资源
    最近更新 更多