具有startAt和endAt的Firebase OrderByKey给出错误的结果

kir*_*403 5 javascript firebase firebase-realtime-database

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

在此输入图像描述

它们的格式为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);
    });
});
Run Code Online (Sandbox Code Playgroud)

我得到以下输出:

objects: 3
20160822-KPl446bbdlaiQx6BOPL
20160901-KPl48ID2FuT3tAVf4DW
20160902-KPl4Fr4O28VpsIkB70Z
Run Code Online (Sandbox Code Playgroud)

当我与endAt一起查询时:

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

我明白了:

objects: 0
Run Code Online (Sandbox Code Playgroud)

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

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

我得到输出:

objects: 3
20160822-KPl446bbdlaiQx6BOPL
20160901-KPl48ID2FuT3tAVf4DW
20160902-KPl4Fr4O28VpsIkB70Z
Run Code Online (Sandbox Code Playgroud)

这里有什么我想念的吗?

Fra*_*len 11

哇......这花了一些时间来挖掘.感谢jsfiddle,这帮了很多忙.

TL; DR:确保你总是有一个非数字字符的搜索条件,如ref.orderByKey().startAt("20160901-").endAt("20160931~").

更长的解释

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

"0": "First"
"1": "Second"
"2": "Third"
Run Code Online (Sandbox Code Playgroud)

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

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

在您的情况下,因为您只查询数值,它将切换到此数字查询模式.但由于你的密钥实际上都是字符串,所以没有什么能比得上

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

更快的解决方法是确保您的条件不可转换为数字.在第一个片段中,我通过添加一个非常低范围的ASCII字符startAt()和一个非常高的ASCII字符来实现这一点endAt().

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