ajonp
ajonp

Reputation: 111

flutter firebase_database joining two nodes

Typically you can use a map function in javascript to update the data coming back. I can not seem to find a method to allow for this in Dart Streams.

Example https://firebase.googleblog.com/2013/10/queries-part-1-common-sql-queries.html

var fb = new Firebase("https://examples-sql-queries.firebaseio.com/");
fb.child('user/123').once('value', function(userSnap) {
   fb.child('media/123').once('value', function(mediaSnap) {
       // extend function: https://gist.github.com/katowulf/6598238
       console.log( extend({}, userSnap.val(), mediaSnap.val()) );
   });
});

I was trying this using the flutter firebase_database.

  var _fireFollower =FirebaseDatabase.instance.reference()
      .child('followers/' + auth.currentUser.uid);
  _fireFollower.onValue.map((snap){
    print(snap.snapshot.key);
  });

However the map function never gets called so I cannot join any other data when it gets fetched from Firebase.

Also the end of this what I am trying to use is a FirebaseAnimatedList, so how can I pass a Query if I don't do a map??

new FirebaseAnimatedList(
query: _fireFollower,
  sort: (a, b) => b.key.compareTo(a.key),
  padding: new EdgeInsets.all(8.0),
  reverse: false,
  itemBuilder: (_, DataSnapshot snapshot,
    Animation<double> animation) {
    return new Activity(
     snapshot: snapshot, animation: animation);
    },
    ),

Upvotes: 2

Views: 2211

Answers (2)

ajonp
ajonp

Reputation: 111

I think this is the suggested solution by @collin-jackson, here is my code...

 return new Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: <Widget>[
                    new Flexible(
                      child: new FirebaseAnimatedList(
                        query: FirebaseDatabase.instance
                                .reference()
                                .child('followers/${auth.currentUser.uid}'),
                        sort: (a, b) => b.key.compareTo(a.key),
                        padding: new EdgeInsets.all(8.0),
                        reverse: false,
                        itemBuilder: (_, DataSnapshot followerSnap,
                            Animation<double> animation) {
                          return new FutureBuilder<DataSnapshot>(
                            future: FirebaseDatabase.instance
                                .reference()
                                .child('users/${followerSnap.key}')
                                .once(),
                            builder: (BuildContext context,
                                AsyncSnapshot<DataSnapshot> userSnap) {
                              switch (userSnap.connectionState) {
                                case ConnectionState.none:
                                  return new Text('Loading...');
                                case ConnectionState.waiting:
                                  return new Text('Awaiting result...');
                                default:
                                  if (userSnap.hasError)
                                    return new Text(
                                        'Error: ${userSnap.error}');
                                  else
                                    return new User(snapshot: userSnap.data, animation: animation);
                              }
                            },
                          );
                        },
                      ),
                    ),
                  ]);

Class for User

@override
class User extends StatelessWidget {
  User({this.snapshot, this.animation});
  final DataSnapshot snapshot;
  final Animation animation;

  Widget build(BuildContext context) {

    return new SizeTransition(
      sizeFactor: new CurvedAnimation(parent: animation, curve: Curves.easeOut),
      axisAlignment: 0.0,
      child: new Container(
        margin: const EdgeInsets.symmetric(vertical: 10.0),
        child: new Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            new Container(
              margin: const EdgeInsets.only(right: 16.0),
              child: snapshot.value['photoURl'] == null
                  ? new CircleAvatar()
                  : new CircleAvatar(
                backgroundImage: new NetworkImage(snapshot.value['photoURl']),
              ),
            ),
            new Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                new Text(snapshot.value['displayName'],
                    style: Theme.of(context).textTheme.subhead),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

Followers, referencing Users.

Upvotes: 0

Collin Jackson
Collin Jackson

Reputation: 116848

In Flutter, DatabaseReference.onValue is a Stream, so you have to call Stream.listen on it and cancel your StreamSubscription when you're done listening. If you just want to get one value event, you should instead call once() to get a Future representing the snapshot value. When it completes, you'll have your snapshot.

Future.wait([fb.child('media/123').once(), fb.child('user/123').once()])
  .then((snapshots) => print("Snapshots are ${snapshots[0]} ${snapshots[1]}"));

This can be even simpler if you do it in an async function because you can just call await to get the result of once():

print("Snapshots are ${await ref1.once()} ${await ref2.once()}");

Upvotes: 1

Related Questions