带有startAt和endAt的Firebase OrderByKey错误结果

时间:2016-08-22 09:47:39

标签: javascript firebase firebase-realtime-database

我有三个带有键的对象,如下所示:

enter image description here

它们的格式为YYYYMMDD。我想获得一个月的数据。但我没有得到理想的输出。

当我这样查询时:

var ref = db.child("-KPXECP6a1pXaM4gEYe0");

ref.orderByKey().startAt("20160901").once("value", function (snapshot) {
    console.log("objects: " + snapshot.numChildren());
    snapshot.forEach(function(childSnapshot) {
        console.log(childSnapshot.key);
    });
});

我得到以下输出:

objects: 3
20160822-KPl446bbdlaiQx6BOPL
20160901-KPl48ID2FuT3tAVf4DW
20160902-KPl4Fr4O28VpsIkB70Z

当我与endAt:

一起查询时
ref.orderByKey().startAt("20160901").endAt("20160932").once("value", function (snapshot) {
    console.log("objects: " + snapshot.numChildren());
    snapshot.forEach(function(childSnapshot) {
        console.log(childSnapshot.key);
    });
});

我明白了:

objects: 0

如果我在最后使用〜符号,

ref.orderByKey().startAt("20160901").endAt("20160932~").once("value", function (snapshot) {
    console.log("objects: " + snapshot.numChildren());
    snapshot.forEach(function(childSnapshot) {
        console.log(childSnapshot.key);
    });
});

我得到了输出:

objects: 3
20160822-KPl446bbdlaiQx6BOPL
20160901-KPl48ID2FuT3tAVf4DW
20160902-KPl4Fr4O28VpsIkB70Z

这里有什么我想念的吗?

1 个答案:

答案 0 :(得分:10)

哇...这需要一些时间来挖掘。感谢jsfiddle,这有很多帮助。

TL; DR:确保您的搜索条件中始终包含非数字字符,例如: ref.orderByKey().startAt("20160901-").endAt("20160931~")

更长的解释

在Firebase中,所有键都存储为字符串。但是我们使开发人员可以在数据库中存储数组。为了允许我们将数组索引存储为字符串属性。所以ref.set(["First", "Second", "Third"])实际上存储为:

"0": "First"
"1": "Second"
"2": "Third"

当您从Firebase获取数据时,它会再次将其转换为数组。但是对于当前的用例来说,理解它是作为键值对存储在字符串键中非常重要。

执行查询时,Firebase会尝试检测您是否正在查询数值范围。当它认为这是你的意图时,它会将参数转换为数字,并根据服务器上密钥的数字转换进行查询。

在您的情况下,因为您只查询数值,它将切换到此数字查询模式。但由于你的密钥实际上都是字符串,所以没有任何东西可以匹配。

出于这个原因,我建议你用常量字符串作为前缀。任何有效的角色都可以,我在测试中使用了-。这会欺骗我们的“它是一个阵列吗?”检查,一切都会以你想要的方式运作。

更快的解决方法是确保您的条件不可转换为数字。在第一个片段中,我通过向startAt()添加一个非常低范围的ASCII字符和一个非常高的ASCII字符endAt()来完成此操作。

这两种方法都是Firebase处理数组的方法。不幸的是,API没有一种简单的方法来处理它,并且需要这样的解决方法。