Firebase中的三向关系

时间:2015-04-21 22:28:11

标签: json firebase firebase-realtime-database database nosql

过去几个月我一直在学习非规范化数据,但是我想知道在扁平化的架构世界中是否有以下几种可能。我知道如何处理Firebase中的双向关系,但是三方关系呢?让我解释一下......

我的数据库中有5个项目,servicesprovidersserviceAtProviderreviewsusers。我希望能够将providers添加到services,反之亦然。

我还希望在provider内有一个service的特定页面,并且在该特定服务上有与该提供商相关联的评论。页面网址可能如下所示(site.com/serviceId/providerId)。该评分对于providerIdserviceId的评分是唯一的 - 您无法单独评价serviceIdproviderId

我不确定如何创建如此复杂的关系。如何加入serviceId项目中的providerIdserviceAtProvider

这是我到目前为止所得到的:

 "services": {
   "service1": {
     "name": "Hernia Repair",
     "providers": {
       "provider1": true,
       "provider2": true
     }
   }
 },
 "providers": {
   "provider1": { "name": "The Whittington Hospital" },
   "provider2": { "name": "Homerton Hospital" }
 },
 "serviceAtProvider": {
   "service1AtProvider1": { "rating": 4 },
   "service1AtProvider2": { "rating": 3 }
 },
 "reviews": {
   "service1AtProvider1": {
     "review1": {
       "body": "A review from user 1",
       "user": "user1"
     }
   },
   "service1AtProvider2": {
     "review1": {
       "body": "A review from user 2",
       "user": "user2"
     }
   }
 },
 "users": {
   "user1": { "name": "Ben Thomas" },
   "user2": { "name": "Beatrix Potter" }
 }

我不知道如何创建serviceAtProvider加入,或者我将如何访问service1.nameprovider1.nameservice1AtProvider1.ratingreviews.service1AtProvider1在一页上。任何人都可以解释如何做到这一点吗?

此外,我应该遵循哪些最佳做法?

感谢任何帮助。提前谢谢!

更新

{
  "availableServices": {
    "service1": { "name": "Hernia Repair" },
    "service2": { "name": "Chemotherapy" }
  },

  "services": {
    "provider": {
      "name": "The Whittington Hospital",
      "service": {
        "service1": {
          "rating": 4,
          "reviewId1": true
        },
        "service2": {
          "rating": 3,
          "reviewId2": true
        },
      }
    }
  },

  "reviews": {
    "reviewId1": {
      "review1": {
        "rating": 4,
        "body": "A review from user 1",
        "user": "user1"
      }
    }
  },

  "users": {
    "user1": { "name": "Raphael Essoo-Snowdon" },
    "user2": { "name": "Sharlyne Slassi" }
  }
}

1 个答案:

答案 0 :(得分:2)

我首先要使数据结构更简单,更直接。没有详细的用例,很难根据需要确定正确的数据结构。我会尽力在这里做一些通用的假设。你必须根据需要进行调整。

{
  "service": {
    "service1": { "name": "Foo Service" }, 
    ...
  },

  "provider": {
     "provider1": { name: "Foo Place" }, 
     ...
  },

  "ratings": {
    "service1": { // service id
      "provider1": {  // provider id
        "average_rating": 4
      },
      ...
    },
    ...
  },

  "reviews": {
    "service1": { // service id
      "provider1": {  // provider id
        "user": "user1",
        "rating": 4
      },
      ...
    },
    ...
  },

  "user": {
    "user1": { "name": "Foo Bar" },
    ...
  }
}

现在,要查找提供给定服务的提供商并获取他们的评论,我会执行以下操作:

var ref = new Firebase(...);
ref.child('ratings/service1').on('child_added', function(reviewSnap) {
   console.log(
      'Provider ' + reviewSnap.key(),
      'Average rating ' + reviewSnap.val().average_rating
   );
});

加入服务和提供者的名称可以通过多种方式完成。这是一种手动技术:

var ref = new Firebase(...);
ref.child('ratings/service1').on('child_added', accumulateReview);

function accumulateReview(reviewSnap) {
  var reviewData = reviewSnap.val();
  var reviewid = reviewSnap.key();
  fetchService(reviewSnap.parent().key(), function(serviceSnap) {
    loadRec('provider', reviewSnap.key(), function(providerSnap) {
        console.log('Provider: ', providerSnap.key(), providerSnap.val().name);
        console.log('Service: ', serviceSnap.key(), serviceSnap.val().name);
        console.log('Average rating: ', reviewData.average_rating);
    });
  });
}

var serviceCache = {};
function fetchService(serviceid, done) {
  // demonstrates creating a local cache for things that will be
  // looked up frequently 
  if( !serviceCache.hasOwnProperty(serviceid) ) {
    cacheService(serviceid, done);
  }
  else {
    done(serviceCache[serviceid]);
  }
}

function cacheService(serviceid, done) {
  loadRec('service', function(ss) {
    serviceCache[serviceid] = ss;
    fetchService(serviceid, done);
  });
}

function loadRec(type, key, done) {
  ref.child(type).child(key).once('value', done);
}

我还可以使用Firebase.util NormalizedCollection自动完成部分过程:

var ref = new Firebase(...);
var nc = Firebase.util.NormalizedCollection(
   [ref.child('reviews/service1'), 'review'],
   ref.child('provider'),
   ref.child('user')
)
.select('review.rating', {key: 'provider.name', alias: 'providerName'}, {key: 'user.name', alias: 'userName'})
.ref();

nc.on('child_added', function(snap) {
  var data = snap.val();
  console.log('Provider', data.providerName);
  console.log('User', data.userName);
  console.log('Rating', data.rating);
});

请注意,这里没有任何内容。这就是我接近它的方式。可能有数十种结构至少同样好或更好。