Firebase 数据标准化.我应该如何根据这个结构获取一个集合? [英] Firebase data normalized. How should I fetch a collection based on this structure?

查看:37
本文介绍了Firebase 数据标准化.我应该如何根据这个结构获取一个集合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想我已经接近了,我能够打印出属于用户的书籍 ID,但一直尝试从 firebase 书籍参考中获取属于用户的书籍列表,但没有成功.

我在这里松散地遵循教程:http://www.thinkster.io/pick/eHPCs7s87O/angularjs-tutorial-learn-to-rapidly-build-real-time-web-apps-with-firebase#item-526e9330d90f99661f00046c

并在此处阅读有关非规范化数据的文档:https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html

如果我想在一个页面中显示用户,然后是所有书籍,我应该怎么做?

firebase 结构

FB|- 用户|||--user1|||--name: "测试名称"|--email: "test@test.com"|- 图书|||-JFZG3coHOAblHZ7XSjK":真|-KJKJASDIOPIWE9WEeJ":真|-YtUTRGJLNL876F3SSwS":真|- 图书|--"-JFZG3coHOAblHZ7XSjK"|||--title: "书名 1"|--ownerId: "user1"|--"-KJKJASDIOPIWE9WEeJ"|||--title: "书名 2"|--ownerId: "user1"|--"-YtUTRGJLNL876F3SSwS"|||--title: "书名 2"|--ownerId: "user1"

查看

<h2>个人资料</h2><img class="image_preview" data-ng-src="{{user.photoUrl}}"><p>姓名:{{用户名}}</p><p>姓名:{{ user.email }}</p><a data-ng-href="#/users/{{ userId }}/edit">编辑</a><h2>咖啡混合物</h2><div data-ng-repeat="book in user.books"><p>---</p><p>{{user.books}}</p>

<!--<div data-ng-controller="BooksController" data-init="">--><!--</div>-->

控制器

'use strict';angular.module('ccApp.controllers.users', ['ccApp.services.users']).controller('UsersController', ['$scope', '$routeParams', '$location', 'angularFire', 'Users',功能($scope,$routeParams,$location,angularFire,用户){$scope.user = {};$scope.userId = $routeParams.userId;$scope.findOneUser = 函数(用户 ID){如果 (!!$scope.userId){angularFire(Users.find($routeParams.userId), $scope, 'user');}};$scope.updatePhotoUrl = 函数(网址,用户){$scope.fileUrl = url;console.log($scope.fileUrl[0].url);user.photoUrl = $scope.fileUrl[0].url;};$scope.findUsers = function(){$scope.users = Users.collection();};$scope.findWholesalers = function(){$scope.wholesalers = Users.collection();};}]);

服务

'use strict';angular.module('ccApp.services.users', ['ccApp.services.firebaseRefs']).factory('用户', ['angularFireCollection', 'FireRef',功能(angularFireCollection,FireRef){返回{集合:函数(cb){返回 angularFireCollection(FireRef.users(), cb);},找到:功能(用户ID){返回 FireRef.users().child('/'+userId);}};}]);

解决方案

从更新到 angularFire 0.6 开始.这看起来是 0.3.*ish.angularFire 已更改为 $firebase 并具有更强大和简化的界面.

Vanilla Firebase

我会先用困难的方法来做这件事,因为我认为理解这里的基本原理很有价值.它相当复杂,我将只介绍基本要素.还有很多微小的边缘情况需要处理:

angular.module('app', []).controller('UsersController', function($scope, $firebase, $timeout, $routeParams){var userId = $routeParams.userId;$scope.user = $firebase(new Firebase('URL/user/'+userId));//或者,对于 3 向绑定和自动写回 Firebasevar userRef = $firebase(new Firebase('URL/users/'+userId)).$bind($scope.'user');//使用 Firebase 获取用户的书籍(困难的方法)$scope.books = {};var bookRef = new Firebase('URL/books/');//动态获取用户的图书列表,因为它可能会实时变化var indexRef = new Firebase('URL/user/'+userId+'/books');//观察添加事件的索引indexRef.on('child_ added', 函数(indexSnap) {//获取这本书并将其放入我们的列表中var bookId = indexSnap.name();bookRef.child(bookId).on('value', function(bookSnap) {//触发 $digest/$apply 以便 Angular 同步 DOM$超时(功能(){if( snap.val() === null ) {//这本书被删除了删除 $scope.books[bookId];}别的 {$scope.books[bookId] = snap.val();}});});});//观察移除事件的索引indexRef.on('child_removed', function(snap) {//触发 $digest/$apply 以便 Angular 更新 DOM$超时(功能(快照){删除 $scope.books[snap.name()];});});});

然后是 HTML(对于下面的其他示例,这将是相同的):

{{bookId}}:{{book.title}}

此处未完全涵盖的一些边缘情况:

  • 数据未按优先级排序
  • 当从索引中删除记录时,应在数据路径上调用 off()
  • 索引顺序的改变不会改变数据记录的顺序
  • 索引的值不会存储在任何地方以供参考(如果重要)

FirebaseIndex

FirebaseIndex 是一个简单的实用程序,它采用像您的书单这样的索引并稍微管理我们刚刚在上面创建的代码老练的方式.

不幸的是,FirebaseIndex 不支持 value 事件,因此它不能在 0.5.0 之后与 angularFire 一起使用,因为 angularFire 的内部加载机制发生了变化.所以它不像以前那样简短和甜蜜.

angular.module('app', []).controller('UsersController', function($scope, $firebase, $timeout){var userId = $routeParams.userId;$scope.user = $firebase(new Firebase('URL/user/'+userId));var fb = new Firebase(URL);var index = new FirebaseIndex( fb.child('user/'+userId+'/books') );$scope.books = {};//几乎是魔法index.on('child_ added', function(snap) {$timeout(function() { $scope.books[snap.name()] = snap.val(); });});index.on('child_removed', function(snap) {$timeout(function() { delete $scope.books[snap.name()]; });});});

Firebase.util.join

Firebase-util 是一个更强大、更复杂的路径规范化库.因为它返回的对象与常规 Firebase 引用一样工作,所以它也可以与 angularFire 0.5 及更高版本无缝使用.

angular.module('app', []).controller('UsersController', function($scope, $firebase){var userId = $routeParams.userId;$scope.user = $firebase(new Firebase('URL/user/'+userId));var fb = new Firebase(URL);var ref = new Firebase.util.intersection( fb.child('user/'+userId+'/books'), fb.child('books') );//魔法!$scope.books = $firebase(ref);});

I think I am getting close, I am able to print out the ID of books belonging to a user but have been trying unsuccessfully to fetch the list of books belonging to a user, from the firebase books reference.

I'm following loosely the tutorial here: http://www.thinkster.io/pick/eHPCs7s87O/angularjs-tutorial-learn-to-rapidly-build-real-time-web-apps-with-firebase#item-526e9330d90f99661f00046c

and also reading the documentation about denormalizing data here: https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html

How should I go about it if I want to display the user in a page, followed by all its books?

firebase structure

FB
|
--user
| |
| --user1
|   |
|   --name: "test name"
|   --email: "test@test.com"
|   --books
|     |
|     "-JFZG3coHOAblHZ7XSjK": true
|     "-KJKJASDIUOPIWE9WEeJ": true
|     "-YtUTRGJLNL876F3SSwS": true
|
--books
  |
  --"-JFZG3coHOAblHZ7XSjK"
  | |
  | --title: "book title 1"
  | --ownerId: "user1"
  |
  --"-KJKJASDIUOPIWE9WEeJ"
  |  |
  |  --title: "book title 2"
  |  --ownerId: "user1" 
  |    
  --"-YtUTRGJLNL876F3SSwS"
  |  |
  |  --title: "book title 2"
  |  --ownerId: "user1" 

View

<div data-ng-controller="UsersController" data-ng-init="findOneUser()">
  <h2>Profile</h2>
  <img class="image_preview" data-ng-src="{{user.photoUrl}}">
  <p>Name: {{ user.name }}</p>
  <p>Name: {{ user.email }}</p>
  <a data-ng-href="#/users/{{ userId }}/edit">Edit</a>

  <h2>Coffee Blends</h2>

  <div data-ng-repeat="book in user.books">
    <p>---</p>
    <p>{{user.books}}</p>
  </div>
  <!--<div data-ng-controller="BooksController" data-init="">-->

  <!--</div>-->
</div>

Controller

'use strict';

angular.module('ccApp.controllers.users', ['ccApp.services.users'])
    .controller('UsersController', ['$scope', '$routeParams', '$location', 'angularFire', 'Users',
      function($scope, $routeParams, $location, angularFire, Users){

      $scope.user = {};
      $scope.userId = $routeParams.userId;

      $scope.findOneUser = function(userId){
        if (!!$scope.userId){
          angularFire(Users.find($routeParams.userId), $scope, 'user');
        }
      };

      $scope.updatePhotoUrl = function(url, user){
        $scope.fileUrl = url;
        console.log($scope.fileUrl[0].url);
        user.photoUrl = $scope.fileUrl[0].url;
      };

      $scope.findUsers = function(){
        $scope.users = Users.collection();
      };

      $scope.findWholesalers = function(){
        $scope.wholesalers = Users.collection();
      };

    }]);

Service

'use strict';

angular.module('ccApp.services.users', ['ccApp.services.firebaseRefs'])
  .factory('Users', ['angularFireCollection', 'FireRef',
    function(angularFireCollection, FireRef){
      return{
        collection: function(cb){
          return angularFireCollection(FireRef.users(), cb);
        }
      , find: function(userId){
          return FireRef.users().child('/'+userId);
        }
      };
  }]);

解决方案

Begin by updating to angularFire 0.6. This looks 0.3.*ish. angularFire has been changed to $firebase and has a much more powerful and simplified interface.

Vanilla Firebase

I'll do this the hard way first as I think there is great value in understanding the underlying principle here. It's fairly complex, and I'll only cover the essentials. There are a lot of tiny edge cases to be handled as well:

angular.module('app', [])
    .controller('UsersController', function($scope, $firebase, $timeout, $routeParams){
      var userId = $routeParams.userId;
      $scope.user = $firebase(new Firebase('URL/user/'+userId));

      // or, for 3-way binding and automatic writes back to Firebase
      var userRef = $firebase(new Firebase('URL/users/'+userId)).$bind($scope. 'user');

      // grab this users' books using Firebase (the hard way)
      $scope.books = {};
      var booksRef = new Firebase('URL/books/');

      // fetch the user's book list dynamically because it may change in real-time
      var indexRef = new Firebase('URL/user/'+userId+'/books');

      // watch the index for add events
      indexRef.on('child_added', function(indexSnap) {
         // fetch the book and put it into our list
         var bookId = indexSnap.name();
         booksRef.child(bookId).on('value', function(bookSnap) {
            // trigger $digest/$apply so Angular syncs the DOM
            $timeout(function() {
               if( snap.val() === null ) {
                  // the book was deleted
                  delete $scope.books[bookId];
               }
               else {
                  $scope.books[bookId] = snap.val();
               }
            });
         });
      });

      // watch the index for remove events
      indexRef.on('child_removed', function(snap) {
         // trigger $digest/$apply so Angular updates the DOM
         $timeout(function(snap) {
            delete $scope.books[snap.name()];
         });
      });
});

Then the HTML (this will be the same for the other examples below):

<div data-ng-repeat="(bookId, book) in books">
   {{bookId}}: {{book.title}}
</div>

Some of the edge cases not fully covered here:

  • data is not sorted by priority ordering
  • when a record is deleted from index, should call off() on data paths
  • changes in ordering of the index won't change order of data records
  • value of the index is not stored anywhere for reference (if it matters)

FirebaseIndex

FirebaseIndex is a simple utility that takes an index like your book list and manages the code we just created above in a bit more sophisticated manner.

Unfortunately, FirebaseIndex doesn't support value events, so it can't be used with angularFire after 0.5.0 because of a change to angularFire's internal loading mechanisms. So it's not quite as short and sweet as it used to be.

angular.module('app', [])
.controller('UsersController', function($scope, $firebase, $timeout){
   var userId = $routeParams.userId;
   $scope.user = $firebase(new Firebase('URL/user/'+userId));

   var fb = new Firebase(URL);
   var index = new FirebaseIndex( fb.child('user/'+userId+'/books') );
   $scope.books = {};

   // almost magic
   index.on('child_added', function(snap) {
      $timeout(function() { $scope.books[snap.name()] = snap.val(); });
   });

   index.on('child_removed', function(snap) {
      $timeout(function() { delete $scope.books[snap.name()]; });
   });
});

Firebase.util.join

Firebase-util is a much more powerful and sophisticated library for normalizing paths. Because it returns an object that works just like a regular Firebase reference, it can also be used seamlessly with angularFire 0.5 and above.

angular.module('app', [])
.controller('UsersController', function($scope, $firebase){
   var userId = $routeParams.userId;
   $scope.user = $firebase(new Firebase('URL/user/'+userId)); 

   var fb = new Firebase(URL);
   var ref = new Firebase.util.intersection( fb.child('user/'+userId+'/books'), fb.child('books') );

   // magic!
   $scope.books = $firebase(ref);
});

这篇关于Firebase 数据标准化.我应该如何根据这个结构获取一个集合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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