在过去的几个月里,我学到了很多关于去规范化数据的知识,但我想知道在扁平化的体系结构世界中,以下内容是否可行。我知道如何在Firebase中处理双向关系,但三方关系呢。让我解释一下。。。
我的数据库中有5个项目,services
、providers
、serviceAtProvider
、reviews
和users
。我希望能够将providers
添加到services
,反之亦然。
我还希望在service
中有一个provider
的特定页面,并且有链接到该特定服务提供商的评论。页面url可能如下所示(site.com/serviceId/providerId
)。serviceId
内的providerId
的评级是唯一的——您不能分别对serviceId
s或providerId
s进行评级。
我不知道如何去建立这样一种复杂的关系。我将如何加入serviceAtProvider
项目中的serviceId
和providerId
?
这就是我目前所掌握的:
"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.name
、provider1.name
、service1AtProvider1.rating
、reviews.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" }
}
}
我首先会让数据结构更简单、更直接。如果没有详细的用例,很难确定适合您需求的正确数据结构。我将尽我所能在这里做一些一般性的假设。你必须根据需要进行调整。
{
"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);
});
请注意,这里没有什么是一成不变的。这就是我的做法。可能有几十种结构至少同样好或更好。