如何在Firestore中进行内部联接 [英] How to inner-join in firestore

查看:70
本文介绍了如何在Firestore中进行内部联接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to build a view to show some events inside a listview in my app like this:

我有这两个表:


用户

Users


事件

Events

但我不知道该怎么办 USERS EVENTS ...

But I don't know how do a "inner join" between the tables USERS and EVENTS...

我尝试过这个:

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,),
                ],
              )
            ]
          )          
        ],
      )
    );
  }
}

但是每次我尝试显示这些事件时,得到此异常

But every time that I try to show these events I get this exception

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

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

What I'm doing wrong? How I can do a "inner join" between thesse tables and show the events?

我正在使用Firebase Firestore。

I'm using the Firebase Firestore.

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

PS: I already know that Firestore is a noSQL database and have no "joins", but I want to do something like a join.

推荐答案

正如我刚才所说,Firestore不支持多集合查询,因为它没有关系数据库。如果需要访问多个集合,则可以独立管理查询。

As I was telling in the coments Firestore does not support multi collection querys cause its no relational DB. If you need to access multiple collections you would manage querys independently.

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

This is how I usually get related collections data (Sorry this is JS code but I dont know 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
}

            })


        })

    })

这篇关于如何在Firestore中进行内部联接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆