【问题标题】:How to inner-join in firestore如何在 Firestore 中进行内部连接
【发布时间】:2019-03-22 18:20:56
【问题描述】:

我想构建一个视图来在我的应用程序的列表视图中显示一些事件,如下所示:

我有这两张表:

用户

 

活动

但我不知道如何在表 USERSEVENTS 之间进行“内部连接”...

我试过了:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:project/Methods.dart';
import 'package:project/Views/CadastroUsuario.dart';
import 'dart:math';

class EventClass{
  String owner;
  String description;
  String city;
  String state;
  String place;
}

class EventsListing extends StatefulWidget {
  @override
  EventsListingState createState() => new EventsListingState();
}

class EventsListingState extends State<EventsListing> {
  List<EventClass> events;

  @override
  void initState() {
    super.initState();
    events = new List<EventClass>();
  }

  void buildEventClass(DocumentSnapshot doc) async {
    EventClass oneEvent = new EventClass();

    DocumentReference document = Firestore.instance.collection("users").document(doc["userid"]);

    document.get().then((DocumentSnapshot snapshot){
      oneEvent.owner = snapshot["name"].toString();
    });
    oneEvent.description = doc["description"];
    oneEvent.place       = doc["place"];
    oneEvent.city        = doc["city"];
    oneEvent.state       = doc["state"];
    events.add(oneEvent);
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Events'), 
      ),
      body: new StreamBuilder(
        stream: Firestore.instance.collection("events").snapshots(),
        builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
          if (snapshot.connectionState == ConnectionState.waiting)
            return Text("Loading...");

          return new ListView(
            padding: EdgeInsets.only(left: 5.0, right: 5.0, top: 5.0),
            children: snapshot.data.documents.map((document){
               buildEventClass(document);
               return events.length == 0 ? new Card() : item(events.last);
              }).toList()
          );
        },
      ),
      floatingActionButton: new FloatingActionButton(
        tooltip: 'New',
        child: new Icon(Icons.add),
        onPressed: () async {
          Navigation navigation = new Navigation();
          navigation.navigaTo(context, CadastroUsuario());
         },
      ),
    );
  }

  Widget item(EventClass oneEvent) {
    return new Card(
      elevation: 4.0,
      child: new Column(
        children: <Widget>[
          new Row(
            children: <Widget>[
              new Column(
                children: <Widget>[
                  new Text(oneEvent.owner.toString(),
                    style: TextStyle(fontSize: 20.0),
                    overflow: TextOverflow.ellipsis,),
                ],
              ),
              new Column(
                children: <Widget>[

                ],
              )
            ],
          ),
          new Container(
            color: Colors.blue,
            height: 150.0,
          ),
          new Row(
            children: <Widget>[
              new Row( 
                children: <Widget>[
                  new Text(oneEvent.description.toString(), 
                    style: TextStyle(fontSize: 20.0),
                    overflow: TextOverflow.ellipsis,),
                ],
              ),
              new Row( 
                children: <Widget>[
                  new Text(oneEvent.place.toString(), 
                    style: TextStyle(color: Colors.grey[350]),
                    overflow: TextOverflow.ellipsis,),
                ],
              ),
              new Row( 
                children: <Widget>[
                  new Text(oneEvent.city.toString() +' - '+ oneEvent.state.toString(), 
                    style: TextStyle(color: Colors.grey[350]),
                    overflow: TextOverflow.ellipsis,),
                ],
              )
            ]
          )          
        ],
      )
    );
  }
}

但每次我尝试显示这些事件时,我都会收到此异常

Exception has occurred.
PlatformException(error, Invalid document reference. Document references must have an even number of segments, but users has 1, null)

我做错了什么?如何在这些表之间进行“内部连接”并显示事件?

我正在使用 Firebase Firestore。

PS:我已经知道 Firestore 是一个 noSQL 数据库并且没有“连接”,但我想做一些类似连接的事情。

【问题讨论】:

  • 你说过,firestore 是一个非关系数据库,所以如果你需要合并数据,你可以在你的应用程序/后端代码中完成,就这么简单。无法在 firestore 中一次查询多个集合。
  • 哪一行会引发该错误?
  • @KarloA.López 好的,但是我该怎么做呢?我需要先获取EVENTS 文档,然后再获取USERS 文档?你能帮我举个例子吗?
  • @FrankvanPuffelen 在执行document.get().then((DocumentSnapshot snapshot) 中的方法then() 以填充event.owner 后,我在此方法void buildEventClass(DocumentSnapshot doc) async 的末尾收到错误。
  • @MatheusRibeiro 你好,开始 firebase 没有内部连接,此时我无法编写一些代码,但你可以尝试以下想法(几周前它对我有用):首先,您需要使用firestore.collection('users').snapshot()users 表中获取所有用户,其次,您必须使用where(userIdField, user.Id) 或类似的方式映射每个user 并查询events 表,最后您将按用户获取所有事件。我希望我的帮助是有用的!享受吧!

标签: firebase dart flutter google-cloud-firestore


【解决方案1】:

正如我在评论中所说,Firestore 不支持多集合查询,因为它没有关系数据库。如果您需要访问多个集合,您将独立管理查询。

这是我通常获取相关集合数据的方式(抱歉,这是 JS 代码,但我不知道 DART):

    var data = {};

    //First you get users data
    DocumentReference document = Firestore.collection("users")

    document.get().then((snapshot) => {

        //In this case I will store data in some object, so I can add events as an array for a key in each user object

        snapshot.forEach((userDoc) => {
            var userDocData = userDoc.data()

            if (data[userDoc.id] == undefined) {
                data[userDoc.id] = userDocData
            }

        })

        //So in this moment data object contains users, now fill users with events data

//In this var you count how many async events have been downloaded, with results or not.    
var countEvents = 0

        Object.keys(data).forEach((userDocId) => {

    //Here Im creating another query to get all events for each user

            SnapshotReference eventsForCurrentUserRef = Firestore.collection("events").where("userId", "==", userDocId)

            eventsForCurrentUserRef.get.then((eventsForUserSnapshot) => {
//Count events
countEvents++

                eventsForUserSnapshot.forEach((eventDoc) => {

                    var eventDocData = eventDoc.data()

                    //Check if array exists, if not create it
                    if (data[eventDocData.userId].events == undefined) {
                        data[eventDocData.userId].events = []
                    }

                    data[eventDocData.userId].events.push(eventDocData)


                })

if(countEvents == Object.keys(data).length){
//Lookup for events in every user has finished
}

            })


        })

    })

【讨论】:

  • 没问题,我明白了!谢谢,我稍后再试试
  • 我按照你的建议做了,看起来效果不错,我拿到了文件并填写了一个班级,但我不知道如何在列表视图中显示这个班级,因为 then()函数是一个异步方法,当我尝试构建列表视图时,该类目前为空。
  • 很好的观察,我已经用一些逻辑更新了我的示例,其中我计算了事件结果的数量并将其与用户数量进行比较,所以当计数等于用户数量时,你确定每个用户都有相应的事件数组。
猜你喜欢
  • 2020-02-09
  • 1970-01-01
  • 2018-06-16
  • 2011-03-18
  • 2016-10-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-17
  • 2017-09-03
相关资源
最近更新 更多