【问题标题】:Firebase query based off results of another queryFirebase 查询基于另一个查询的结果
【发布时间】:2021-10-28 20:04:08
【问题描述】:

我正在尝试制作一个包含名称列表的下拉按钮。 下拉列表应显示团队的运动员姓名。 但是,下拉列表仅显示 UID。我无法让它通过 UID 查询帐户以提取正确的名称。

代码:

FutureBuilder(
  future: database.reference().child("teams").child("TID1").child("athletes").once(),
  builder: (context, AsyncSnapshot<DataSnapshot> snapshot) {
    if(snapshot.hasData) {
      aKeys.clear();
      Map<dynamic, dynamic> values = snapshot.data.value;
      values.forEach((key, value) {
        database.reference().child("accounts").child(value).once();
        if (snapshot.hasData) {
          Map<dynamic, dynamic> nameValues = snapshot.data.value;
          nameValues.forEach((key, value) {
            aNames.add(
              DropdownMenuItem<dynamic>(
                child: Text(value["first name"]),
                value: key,
              )
            );
          });
        }
      });
      return Material(
        color: Colors.white,
        child: DropdownButtonHideUnderline(
          child: DropdownButton(
            items: aNames,
            hint: Text("Select an athlete"),
            value: _athlete,
            onChanged: (value) {
              setState(() {
                _athlete = value;
              });
            },
          ),
        ),
      );
    }
    return CircularProgressIndicator();
  }
),

我知道问题出在 values.forEach 中,因为我正在尝试对帐户运行查询以提取名称。我知道这不起作用,因为它不是正确的方法,但我不知道让它工作的正确方法。我尝试在 values.forEach 中添加另一个 FutureBuilder,但这也不起作用。

我想通过查询来找出球队的运动员键是什么,然后将它们放入一个列表中。然后遍历该列表以对帐户运行查询,然后获取名字值并将其添加到具有名字的 DropdownMenuItem 的单独列表中。

JSON 数据:

{
    "accounts" :{
        "UID1" : {
            "first name" : "bob",
            "last name" :  "rogers"
        },
        "UID2" : {
            "first name" : "john",
            "last name" : "smith"
        },
        "UID3" : {
            "first name" : "tim",
            "last name" : "murr"
        },
        "UID4" : {
            "first name" : "larry",
            "last name" : "dean"
        }
    },
    "teams" : {
        "TID1" : {
            "athletes" : {
                "A1" : "UID1",
                "A2" : "UID2"
            }
        },
        "TID2" : {
            "athletes" : {
                "A1" : "UID3",
                "A2" : "UID4"
            }
        }
    }
}

当前代码:

FutureBuilder(
  future: database.reference().child("teams").child("UID").child("athletes").once(),
  builder: (context, AsyncSnapshot<DataSnapshot> snapshot) {
    if(snapshot.hasData) {
      dynamic values = snapshot.data.value;
      return FutureBuilder(
        future: Future.wait<DataSnapshot>(values.map((key, value) {
          return database.reference().child("accounts").child(value).once();
        })),
        builder: (context, AsyncSnapshot<List<DataSnapshot>> snapshots) {
          snapshots.data!.forEach((snapshot) {
            aNames.add(
                DropdownMenuItem<dynamic>(
                  child: Text(snapshot.value["first name"]),
                  value: snapshot.key,
                )
            );
          });
          return Material(
            color: Colors.white,
            child: DropdownButtonHideUnderline(
              child: DropdownButton(
                items: aNames,
                hint: Text("Select an athlete"),
                value: _athlete,
                onChanged: (value) {
                  setState(() {
                    _athlete = value;
                  });
                },
              ),
            ),
          );
        },
      );
    }
    return CircularProgressIndicator();
  }
),

【问题讨论】:

    标签: android flutter firebase-realtime-database


    【解决方案1】:

    您没有处理由once() 在您的调用中返回的Future

    database.reference().child("accounts").child(value).once();
    

    如果您只需要检索一个帐户,您可以使用另一个带有 once() 调用的 FutureBuilder 作为 future 属性,就像您现在为:

    future: database.reference().child("teams").child("TID1").child("athletes").once()
    

    但由于您有多个once(),您必须收集所有这些,然后传递给Future.wait()

    类似这样的:

    FutureBuilder(
      future: database.reference().child("teams").child("TID1").child("athletes").once(),
      builder: (context, AsyncSnapshot<DataSnapshot> snapshot) {
        if(snapshot.hasData) {
          return FutureBuilder(
            future: Future.wait(values.map((key, value) {
              return database.reference().child("accounts").child(value).once();
            }
            builder: (context, AsyncSnapshot<List<DataSnapshot>> snapshots) {
              snapshots.data!.forEach((snapshot) {
                // TODO: get the value from the snapshot and create your dropdown with it
              }
            }
          });
        }
        return CircularProgressIndicator();
      }
    ),
    

    我没有运行这段代码,所以里面可能有一些小问题。我的答案的关键是:您需要使用Future.wait 和另一个FutureBuilder 来处理多个once 调用。

    【讨论】:

    • 嘿,我仍然无法使其正常工作,非常感谢您提供更多帮助
    • “我还是有问题” 这很难解决。你对我回答中的信息做了什么,你遇到了什么问题?
    • 我使用了您放置的内容,基本上添加了我原来缺少的内容,dropdownMenuItem 的添加和实际 DropdownButton 的 Material 返回。这在整个内部 FutureBuilder 中给出了红色错误线,如果不将内部构建器 AsyncSnapshot> 更改为 AsyncSnapshot>,我无法让这些错误线消失。但问题是 Map&lt;dynamic,dynamic&gt; nameValues = snapshots.data.value; 行说 .value 没有为 List 定义。
    • 如果您愿意,我可以继续详细介绍我接下来要做什么,但从那里我已将 List 更改为 DataSnapshot 并删除了 future.wait 以便真正成为能够运行应用程序。但我知道我做的不对,因为我必须夺走未来。等待让它运行。
    • 使用dynamic 不是一个好的解决方案。你试过Future.wait&lt; DataSnapshot&gt;(values.map(...吗?另外:始终检查并分享您收到的确切错误消息,因为这将有助于理解问题。
    猜你喜欢
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 2019-11-05
    • 1970-01-01
    • 2014-08-18
    • 1970-01-01
    • 2011-12-02
    • 1970-01-01
    相关资源
    最近更新 更多