Firebase 反规范化多对多
Firebase denormalizing many to many
我有一个非常基本的数据结构
- 事件
- 话题
我希望能够轻松显示(查询)
活动拥有哪些主题
什么事件涵盖了一个话题
这个月最热门的话题是什么
我对我的活动结构很满意
/events/880088/topics.json *
["Firebase", "Cloud"]
但我对如何构建 /topics 节点感到困惑。我部分地想到了使用
之类的东西
/topics/Firebase
{"12345":true,"88088":true}
然后,如果当我更新事件的主题集合时,我将不得不遍历所有 /topics/ 节点并更新 /topics/{{topic}}/{{eventid}}到{真|无效的}。这看起来有点吝啬。
ALSO,那我现在还不知道怎么查询说,这个月的活动涵盖了哪些话题
以下评论中的 JSBin 示例 http://jsbin.com/dumumu/edit?js,output
*
我知道,我知道,数组是邪恶的,https://www.firebase.com/blog/2014-04-28-best-practices-arrays-in-firebase.html,但我认为它们适合这个场景
这是添加活动的一种方法:
function addEvent(title, topics) {
var event =ref.child('events').push({ title: title });
topics.forEach(function(topic) {
event.child('topics').child(topic).set(true);
ref.child('topics').child(topic).child(event.key()).set(true);
});
}
对我来说似乎很简单。有趣的是,您可以使用新的 multi-location updates we launched yesterday(2015 年 9 月):
function addEvent(title, topics) {
var updates = {};
var eventId = ref.push().key();
updates['events/'+eventId+'/title'] = title;
topics.forEach(function(topic) {
updates['events/'+eventId+'/topics/'+topic] = true;
updates['topic/'+topic+'/'+eventId] = true;
});
ref.update(updates);
}
后者的代码有点多。但这是对 Firebase 的单个写入操作,因此用户不可能在写入操作之间关闭应用程序。
你调用两者当然是一样的:
addEvent('Learn all about Firebase', ['Firebase']);
addEvent('Cloudspin', ['Firebase', 'Google', 'Cloud']);
数据结构变为:
{
"events": {
"-K-4HCzj_ziHkZq3Fpat": {
"title": "Learn all about Firebase",
"topics": {
"Firebase": true
}
},
"-K-4HCzlBFDIwaA8Ajb7": {
"title": "Cloudspin",
"topics": {
"Cloud": true,
"Firebase": true,
"Google": true
}
}
},
"topic": {
"Cloud": {
"-K-4HCzlBFDIwaA8Ajb7": true
},
"Firebase": {
"-K-4HCzj_ziHkZq3Fpat": true,
"-K-4HCzlBFDIwaA8Ajb7": true
},
"Google": {
"-K-4HCzlBFDIwaA8Ajb7": true
}
}
}
Querying/reporting
使用 Firebase(和大多数 NoSQL 数据库),您通常必须根据要对其进行的报告调整数据结构。
Abe 最近就此写了一个很好的答案,所以一定要去读一下:
更新:更改活动主题
如果您想更改现有活动的主题,此功能是完成此操作的一种方式:
function updateEventTopics(event, newTopics) {
newTopics.sort();
var eventId = event.key();
var updates = {};
event.once('value', function(snapshot) {
var oldTopics = Object.keys(snapshot.val().topics).sort();
var added = newTopics.filter(function(t) { return oldTopics.indexOf(t) < 0; }),
removed = oldTopics.filter(function(t) { return newTopics.indexOf(t) < 0; });
added.forEach(function(topic) {
updates['events/'+eventId+'/topics/'+topic] = true;
updates['topic/'+topic+'/'+eventId] = true;
});
removed.forEach(function(topic) {
updates['events/'+eventId+'/topics/'+topic] = null;
updates['topic/'+topic+'/'+eventId] = null;
});
ref.update(updates);
});
}
代码确实有点长,不过主要是为了determine the delta between the current topics and the new topics。
以防你好奇,如果我们 运行 这些 API 现在调用:
var event = addEvent('Cloudspin', Date.now() - month, ['Firebase', 'Google', 'Cloud']);
updateEventTopics(event, ['Firebase', 'Google', 'GCP']);
changeEventTopics()
调用将导致此 update()
:
{
"events/-K-93CxuCrFDxM6k0B14/topics/Cloud": null,
"events/-K-93CxuCrFDxM6k0B14/topics/GCP": true,
"topic/Cloud/-K-93CxuCrFDxM6k0B14": null,
"topic/GCP/-K-93CxuCrFDxM6k0B14": true
}
我有一个非常基本的数据结构
- 事件
- 话题
我希望能够轻松显示(查询)
活动拥有哪些主题
什么事件涵盖了一个话题
这个月最热门的话题是什么
我对我的活动结构很满意
/events/880088/topics.json *
["Firebase", "Cloud"]
但我对如何构建 /topics 节点感到困惑。我部分地想到了使用
之类的东西/topics/Firebase
{"12345":true,"88088":true}
然后,如果当我更新事件的主题集合时,我将不得不遍历所有 /topics/ 节点并更新 /topics/{{topic}}/{{eventid}}到{真|无效的}。这看起来有点吝啬。
ALSO,那我现在还不知道怎么查询说,这个月的活动涵盖了哪些话题
以下评论中的 JSBin 示例 http://jsbin.com/dumumu/edit?js,output
*
我知道,我知道,数组是邪恶的,https://www.firebase.com/blog/2014-04-28-best-practices-arrays-in-firebase.html,但我认为它们适合这个场景
这是添加活动的一种方法:
function addEvent(title, topics) {
var event =ref.child('events').push({ title: title });
topics.forEach(function(topic) {
event.child('topics').child(topic).set(true);
ref.child('topics').child(topic).child(event.key()).set(true);
});
}
对我来说似乎很简单。有趣的是,您可以使用新的 multi-location updates we launched yesterday(2015 年 9 月):
function addEvent(title, topics) {
var updates = {};
var eventId = ref.push().key();
updates['events/'+eventId+'/title'] = title;
topics.forEach(function(topic) {
updates['events/'+eventId+'/topics/'+topic] = true;
updates['topic/'+topic+'/'+eventId] = true;
});
ref.update(updates);
}
后者的代码有点多。但这是对 Firebase 的单个写入操作,因此用户不可能在写入操作之间关闭应用程序。
你调用两者当然是一样的:
addEvent('Learn all about Firebase', ['Firebase']);
addEvent('Cloudspin', ['Firebase', 'Google', 'Cloud']);
数据结构变为:
{
"events": {
"-K-4HCzj_ziHkZq3Fpat": {
"title": "Learn all about Firebase",
"topics": {
"Firebase": true
}
},
"-K-4HCzlBFDIwaA8Ajb7": {
"title": "Cloudspin",
"topics": {
"Cloud": true,
"Firebase": true,
"Google": true
}
}
},
"topic": {
"Cloud": {
"-K-4HCzlBFDIwaA8Ajb7": true
},
"Firebase": {
"-K-4HCzj_ziHkZq3Fpat": true,
"-K-4HCzlBFDIwaA8Ajb7": true
},
"Google": {
"-K-4HCzlBFDIwaA8Ajb7": true
}
}
}
Querying/reporting
使用 Firebase(和大多数 NoSQL 数据库),您通常必须根据要对其进行的报告调整数据结构。
Abe 最近就此写了一个很好的答案,所以一定要去读一下:
更新:更改活动主题
如果您想更改现有活动的主题,此功能是完成此操作的一种方式:
function updateEventTopics(event, newTopics) {
newTopics.sort();
var eventId = event.key();
var updates = {};
event.once('value', function(snapshot) {
var oldTopics = Object.keys(snapshot.val().topics).sort();
var added = newTopics.filter(function(t) { return oldTopics.indexOf(t) < 0; }),
removed = oldTopics.filter(function(t) { return newTopics.indexOf(t) < 0; });
added.forEach(function(topic) {
updates['events/'+eventId+'/topics/'+topic] = true;
updates['topic/'+topic+'/'+eventId] = true;
});
removed.forEach(function(topic) {
updates['events/'+eventId+'/topics/'+topic] = null;
updates['topic/'+topic+'/'+eventId] = null;
});
ref.update(updates);
});
}
代码确实有点长,不过主要是为了determine the delta between the current topics and the new topics。
以防你好奇,如果我们 运行 这些 API 现在调用:
var event = addEvent('Cloudspin', Date.now() - month, ['Firebase', 'Google', 'Cloud']);
updateEventTopics(event, ['Firebase', 'Google', 'GCP']);
changeEventTopics()
调用将导致此 update()
:
{
"events/-K-93CxuCrFDxM6k0B14/topics/Cloud": null,
"events/-K-93CxuCrFDxM6k0B14/topics/GCP": true,
"topic/Cloud/-K-93CxuCrFDxM6k0B14": null,
"topic/GCP/-K-93CxuCrFDxM6k0B14": true
}