Firebase:如何构造查询中的多个位置

Firebase:如何构造查询中的多个位置,firebase,web,firebase-realtime-database,Firebase,Web,Firebase Realtime Database,我在我的小项目中使用Firebase已经快一年了,我非常喜欢它。但由于单个orderByChild()的限制,无法将其用于需要复杂查询的大型项目 仍在考虑将Firebase用于多where子句场景的方法。在我用PHP开发的一个主要项目中,我们有一个查询,如下所示: SELECT * FROM `masterEvents` WHERE causeId IN ( 1, 2, 3, 4, 5, 6, 7, 8 ) AND timeId IN (1, 2, 3, 4) AND localityI

我在我的小项目中使用Firebase已经快一年了,我非常喜欢它。但由于单个orderByChild()的限制,无法将其用于需要复杂查询的大型项目

仍在考虑将Firebase用于多where子句场景的方法。在我用PHP开发的一个主要项目中,我们有一个查询,如下所示:

SELECT * 
FROM  `masterEvents` 
WHERE causeId IN ( 1, 2, 3, 4, 5, 6, 7, 8 ) 
AND timeId IN (1, 2, 3, 4)
AND localityID IN (1, 2, 3, 4, 5)
上面的问题。过滤在特定地点发生、在特定时间段内发生并包含在给定原因下的事件

  • 地方可以有40个
  • 原因大约是20个
  • 时间是21点
解决方案1:所有3个筛选键都作为子项

{
    "eventIndex": {
        "ev1": {
            "name": "Event 1",
            "location": 2,
            "cause": 3,
            "time": 5,
        },
        "ev2": {
            "name": "Event 2",
            "location": 5,
            "cause": 2,
            "time": 1,
        },
        "ev3": {
            "name": "Event 3",
            "location": 26,
            "cause": 12,
            "time": 18,
        }
    }
}

forEach(location in selectedLocationArray) {
    firebase.database().ref("eventIndex").orderByChild("location").equalTo(location).on("value", snap => {
        // loop through all events and filter them based on selectedCauseArray and selectedTimeArray
    });
}
{
    "eventIndex": {
        "location1": {
            "ev1": {
                "name": "Event 1",
                "cause": 2,
                "time": 1,
            },
            "ev2": {
                "name": "Event 2",
                "cause": 12,
                "time": 18,
            }
        },
        "location2": {
            "ev4": {
                "name": "Event 4",
                "cause": 2,
                "time": 1,
            }
        },
        "location3": {
            "ev8": {
                "name": "Event 9",
                "cause": 2,
                "time": 1,
            },
            "ev9": {
                "name": "Event 9",
                "cause": 12,
                "time": 18,
            }
        }
    }
}

forEach(location in selectedLocationArray) {
    forEach(cause in selectedCauseArray) {
        firebase.database().ref("eventIndex/location" + location).orderByChild("cause").equalTo(cause).on("value", snap => {
            // loop through all events and filter them based on selectedTimeArray
        });
    }
}
解决方案2:节点路径中有1个筛选键,子路径中有2个筛选键

{
    "eventIndex": {
        "ev1": {
            "name": "Event 1",
            "location": 2,
            "cause": 3,
            "time": 5,
        },
        "ev2": {
            "name": "Event 2",
            "location": 5,
            "cause": 2,
            "time": 1,
        },
        "ev3": {
            "name": "Event 3",
            "location": 26,
            "cause": 12,
            "time": 18,
        }
    }
}

forEach(location in selectedLocationArray) {
    firebase.database().ref("eventIndex").orderByChild("location").equalTo(location).on("value", snap => {
        // loop through all events and filter them based on selectedCauseArray and selectedTimeArray
    });
}
{
    "eventIndex": {
        "location1": {
            "ev1": {
                "name": "Event 1",
                "cause": 2,
                "time": 1,
            },
            "ev2": {
                "name": "Event 2",
                "cause": 12,
                "time": 18,
            }
        },
        "location2": {
            "ev4": {
                "name": "Event 4",
                "cause": 2,
                "time": 1,
            }
        },
        "location3": {
            "ev8": {
                "name": "Event 9",
                "cause": 2,
                "time": 1,
            },
            "ev9": {
                "name": "Event 9",
                "cause": 12,
                "time": 18,
            }
        }
    }
}

forEach(location in selectedLocationArray) {
    forEach(cause in selectedCauseArray) {
        firebase.database().ref("eventIndex/location" + location).orderByChild("cause").equalTo(cause).on("value", snap => {
            // loop through all events and filter them based on selectedTimeArray
        });
    }
}
解决方案3:节点路径中有2个筛选键,子节点中有1个筛选键

{
    "eventIndex": {
        "ev1": {
            "name": "Event 1",
            "location": 2,
            "cause": 3,
            "time": 5,
        },
        "ev2": {
            "name": "Event 2",
            "location": 5,
            "cause": 2,
            "time": 1,
        },
        "ev3": {
            "name": "Event 3",
            "location": 26,
            "cause": 12,
            "time": 18,
        }
    }
}

forEach(location in selectedLocationArray) {
    firebase.database().ref("eventIndex").orderByChild("location").equalTo(location).on("value", snap => {
        // loop through all events and filter them based on selectedCauseArray and selectedTimeArray
    });
}
{
    "eventIndex": {
        "location1": {
            "ev1": {
                "name": "Event 1",
                "cause": 2,
                "time": 1,
            },
            "ev2": {
                "name": "Event 2",
                "cause": 12,
                "time": 18,
            }
        },
        "location2": {
            "ev4": {
                "name": "Event 4",
                "cause": 2,
                "time": 1,
            }
        },
        "location3": {
            "ev8": {
                "name": "Event 9",
                "cause": 2,
                "time": 1,
            },
            "ev9": {
                "name": "Event 9",
                "cause": 12,
                "time": 18,
            }
        }
    }
}

forEach(location in selectedLocationArray) {
    forEach(cause in selectedCauseArray) {
        firebase.database().ref("eventIndex/location" + location).orderByChild("cause").equalTo(cause).on("value", snap => {
            // loop through all events and filter them based on selectedTimeArray
        });
    }
}
以上哪一项是我可以采取的有效解决方案?谢谢:-)


PS:可以将代码视为伪代码来提供逻辑概念,而不是实际代码。

我发现过滤数据的最有效方法之一是将多个键分组或组合在一起

例如,在您问题中提到的上述结构中,我将添加另一个名为“_idx_location_cause_time”的字段,它是顺序中的值的组合-位置、原因和时间

...
"ev1": {
    "name": "Event 1",
    "location": 2,
    "cause": 3,
    "time": 5,
    "_idx_location_cause_time" : "2_3_5"
},
...
现在我可以使用
orderByChild
query来过滤结果。就是

dbRef.orderByChild(_idx_location_cause_time).equalTo(“2_3_5”)。一次(“value”,…)

这是一个关于如何使用它来构造数据并相应地过滤数据的一般概念。您还可以将此技术与您在问题中提到的技术结合起来,进一步简化过滤过程

在Firebase规则中使用
.indexOn
对其进行索引也很重要,以提高查询的性能


希望这有帮助

对于这个解决方案,我不需要多个组合键吗?因为你可以通过不同的方式过滤combinations@AngularM现在更好的解决方案是使用Firestore编写高级查询将我的firebase实时数据库移动到该位置容易吗