使用startAfter时,Firebase实时数据库查询同时返回列表和映射



我有以下一段代码,为了说明起见,对其进行了简化:

List<Name> _nameList = [];
_getNameList() {
String dbPath = “names/“;
var startAfter = _nameList.length - 1;
final db = FirebaseDatabase.instance
.ref()
.child(dbPath)
.orderByKey()
.startAfter(startAfter.toString())
.limitToFirst(4);
final nameFuture = db.once();
nameFuture.then((event) {
List<Name> nameList = [];
print(event.snapshot.value);
if (event.snapshot.value != null) {
for (var item in (event.snapshot.value as List<Object?>)) {
if (item != null) {
Name d = Name.fromRTDB(item);
nameList.add(d);
}
}
}
if (nameList.isNotEmpty) {
setState(() {
_nameList.addAll(nameList);
});
}
});
}

它最初从Firebase实时数据库中读取前4个Name对象。无论何时调用它,我都希望它读取接下来的4个Name对象,并将它们附加到代码中所述的_nameList中。

重要请注意,实时数据库中每个Name对象的键都是0、1、2、3、4,依此类推。如果我没有完全错的话,这实际上应该会让使用startAfter时的生活更轻松。

正如您可能认识到的,我将来自DB的值打印为print(event.snapshot.value);

第一次读取工作得非常好,其中startAfter设置为"0"-1〃;。print(event.snapshot.value);:的输出示例

[{name: "John"}, {name: "Johanna"}, {name: "Maria"}, {name: "Steve"}]

问题1当我再次运行函数时,startAfter现在是3,我看到以下输出:

[null, null, null, null, {name: "Michael"}, {name: "Maradona"}, {name: "Pelle"}, {name: "Messi"}]

我预计这份清单的大小是4件,但它包括8件。前4个为空为什么我在返回的列表中有8个项目,为什么前4个为空

问题2当我第三次运行该函数时,startAfter现在是7,这次我得到了以下输出:

{10: {name: "Jordan"}, 8: {name: "James"}, 9: {name: "Rambo"}, 11: {name: "Brian"}}

前两个调用返回列表,第三个调用返回映射。为什么在第三次通话中突然返回地图?我用orderByKey((进行调用,但映射中返回的键不按顺序;为什么

问题1:当我再次运行函数时,startAfter现在是3,我看到以下输出:

[null, null, null, null, {name: "Michael"}, {name: "Maradona"}, {name: "Pelle"}, {name: "Messi"}]

这是实时数据库API的预期行为。当它看到一堆(足够(连续的数字键时,它假设数据最初是一个数组,并将数据作为数组返回。由于您的数组在索引[0-3]处没有项,因此这些索引将我们显示为null

这种所谓的数组强制在很大程度上取决于数据,但通常在数组开头有太多(我记不起确切的值(缺失值时就会停止,我认为这可能是导致另一个问题的原因。

解决方案是在实时数据库数据中不使用顺序数字键,而是使用push()函数生成键(推荐(或在数字前面加一个短字符串,例如";key_ 3"key_4";,等

另请参阅:最佳实践:Firebase中的阵列。

最新更新