我已经阅读了有关“ 构建数据”的Firebase文档。数据存储很便宜,但用户的时间却不便宜。我们应该针对get操作进行优化,并在多个地方编写。
因此,我可能会存储一个 列表 节点和一个 列表索引 节点,两者之间有一些重复的数据,至少是列表名称。
我正在使用ES6,并在我的javascript应用程序中承诺处理异步流,主要是在第一次数据推送后从firebase中获取ref键。
let addIndexPromise = new Promise( (resolve, reject) => {
let newRef = ref.child('list-index').push(newItem);
resolve( newRef.key()); // ignore reject() for brevity
});
addIndexPromise.then( key => {
ref.child('list').child(key).set(newItem);
});
知道我的应用程序仅在客户端上运行时,如何确保数据在所有位置均保持同步 ?
为了进行健全性检查,我在诺言中设置了setTimeout,并在浏览器解析前关闭了它,实际上我的数据库不再一致,并且 保存了没有相应列表的额外索引 。
有什么建议吗?
好问题。我知道三种解决方法,下面将列出。
我将为此使用一个稍微不同的示例,主要是因为它允许我在解释中使用更具体的术语。
假设我们有一个聊天应用程序,其中存储了两个实体:消息和用户。在显示消息的屏幕中,我们还显示用户名。因此,为了最大程度地减少读取次数,我们还将在每个聊天消息中存储用户名。
users
so:209103
name: "Frank van Puffelen"
location: "San Francisco, CA"
questionCount: 12
so:3648524
name: "legolandbridge"
location: "London, Prague, Barcelona"
questionCount: 4
messages
-Jabhsay3487
message: "How to write denormalized data in Firebase"
user: so:3648524
username: "legolandbridge"
-Jabhsay3591
message: "Great question."
user: so:209103
username: "Frank van Puffelen"
-Jabhsay3595
message: "I know of three approaches, which I'll list below."
user: so:209103
username: "Frank van Puffelen"
因此,我们将用户配置文件的主副本存储在users
节点中。在消息中,我们存储uid
(so:209103和so:3648524),以便我们可以查找用户。但是,我们还将用户的名称存储在消息中,因此,当我们要显示消息列表时,不必为每个用户查找此名称。
现在,当我转到聊天服务上的“个人资料”页面并将我的名字从“ Frank van Puffelen”更改为“ puf”时,会发生什么。
交易更新
最初,大多数开发人员可能会想到执行事务更新。我们始终希望username
in消息与name
相应配置文件中的in 匹配。
使用多路径写入 (在20150925上添加)
从Firebase 2.3(针对JavaScript)和2.4(针对Android和iOS)开始,您可以使用单个多路径更新来轻松实现原子更新:
function renameUser(ref, uid, name) {
var updates = {}; // all paths to be updated and their new values
updates['users/'+uid+'/name'] = name;
var query = ref.child('messages').orderByChild('user').equalTo(uid);
query.once('value', function(snapshot) {
snapshot.forEach(function(messageSnapshot) {
updates['messages/'+messageSnapshot.key()+'/username'] = name;
})
ref.update(updates);
});
}
这将向Firebase发送一个更新命令,该命令将更新其个人资料和每条消息中的用户名。
先前的原子方法
因此,当用户更改name
了个人资料中的时:
var ref = new Firebase('https://mychat.firebaseio.com/');
var uid = "so:209103";
var nameInProfileRef = ref.child('users').child(uid).child('name');
nameInProfileRef.transaction(function(currentName) {
return "puf";
}, function(error, committed, snapshot) {
if (error) {
console.log('Transaction failed abnormally!', error);
} else if (!committed) {
console.log('Transaction aborted by our code.');
} else {
console.log('Name updated in profile, now update it in the messages');
var query = ref.child('messages').orderByChild('user').equalTo(uid);
query.on('child_added', function(messageSnapshot) {
messageSnapshot.ref().update({ username: "puf" });
});
}
console.log("Wilma's data: ", snapshot.val());
}, false /* don't apply the change locally */);
精打细算,精明的读者会注意到我在处理消息时作弊。首先作弊的是,我从不要求off
侦听器,但我也不使用事务。
如果我们想从客户端安全地进行此类操作,则需要:
username
消息的所有字段更改so:209103
为null
(有些不可思议的值)name
用户的更改so:209103
为“ puf”username
每则消息中的so:209103
是null
要puf
。and
两个条件之一,Firebase查询不支持这些条件。因此,我们将获得一个可以查询的额外属性uid_plus_name
(具有value so:209103_puf
)。这种方法使我的头部受伤。通常,这意味着我做错了事。但是,即使这是正确的方法,但头部受伤,我更有可能犯编码错误。所以我更喜欢寻找一个更简单的解决方案。
最终一致性
:Firebase发布了一项功能,允许对多个路径进行原子写入。这与下面的方法类似,但是使用单个命令。请参阅上面的更新部分,以了解其工作原理。
第二种方法取决于将用户操作(“我想将我的名字更改为’puf””)与该操作的含义(“我们需要在profile:209103中以及每个包含的消息中更新名称)分开”
user = so:209103
。
我将在服务器上运行的脚本中处理重命名。主要方法如下:
function renameUser(ref, uid, name) {
ref.child('users').child(uid).update({ name: name });
var query = ref.child('messages').orderByChild('user').equalTo(uid);
query.once('value', function(snapshot) {
snapshot.forEach(function(messageSnapshot) {
messageSnapshot.update({ username: name });
})
});
}
我在这里再次使用了一些捷径,例如使用once('value'
(使用Firebase获得最佳性能通常不是一个好主意)。但是总体而言,此方法更简单,但代价是无法同时完全更新所有数据。但是最终,消息将全部更新以匹配新值。
不在乎
第三种方法是最简单的方法:在许多情况下,您根本不需要更新重复的数据。在我们这里使用的示例中,您可以说每个消息都记录了我当时使用的名称。直到现在我都没有更改我的名字,所以有意义的是,较旧的消息会显示我当时使用的名称。这在二级数据本质上是事务性的许多情况下适用。当然,它并不是在所有地方都适用,但是在所有情况下,“不关心”是最简单的方法。
摘要
尽管以上只是对如何解决此问题的广泛描述,但是它们肯定还不完整,但我发现,每次需要散出重复数据时,它都会回到这些基本方法之一。
问题内容: 好的,我刚开始使用Firebase。我已阅读:https://www.firebase.com/docs/data- structure.html, 并且已阅读:https://www.firebase.com/blog/2013-04-12-denormalizing- is- normal.html 所以我很困惑,因为一个似乎与另一个矛盾。您可以按层次结构组织数据,但是如果您想使其
非规范化数据不存储规范化的数据。换句话说非规范化意味着相同数据的多个拷贝同时存在。 上一章中,我们在帖子中非规范化评论总数,以避免每次都加载所有的评论。在数据建模意义上说这是冗余的,因为我们可以通过计数每个评论,随时计算出该总数(当不考虑运行速度)。 非规范化通常意味着额外的开发工作。在例子中,我们每次添加或删除评论时,还需要同时更新相关的帖子,以确保 commentsCount 字段保持准确。这
问题内容: 用例说明 我们有一个关系数据库,其中包含有关我们日常运营的数据。目的是允许用户使用全文本搜索引擎来搜索重要数据。数据经过规范化,因此不是进行全文查询的最佳形式,因此,其想法是对数据的一部分进行规范化,然后将其实时复制到Elasticsearch,这使我们能够创建快速而准确的搜索应用程序。 我们已经有了一个启用数据库操作(插入,更新,删除)事件搜索的系统。这些事件仅包含已更改的列和主键(
问题内容: 我正在使用Ruby on Rails 3.0.7和MySQL5。在我的应用程序中,我有两个数据库表,即TABLE1和TABLE2,并且出于性能原因,我对TABLE2中的某些数据进行了非规范化,因此我在该表中重复了TABLE1的值。现在,在TABLE1中,我需要更新一些涉及的值,当然,我还必须在TABLE2中正确地更新非规范化的值。 我该如何以高效的方式更新这些值? 也就是说,如果TAB
我阅读了cassandra数据建模,除了非规范化数据可能会发生变化之外,一切都很清楚。我如何同步它?当用户电子邮件更改时,更新的方法是什么: < code>groupname是组的一部分,数据模型中的用户可能不知道任何组,因此在用户更改后无法更新电子邮件。 下面描述的解决方案是否合适? 向用户模型中添加一列(类型
问题内容: 我想知道是否有人对如何规范化数据库有任何建议。现在,我不是要设计结构,而是要实际将数据库数据从旧结构移动到新的规范化结构。我知道我可以编写类似PHP脚本的内容,但是我想知道是否有一种方法可以在SQL中进行。特别是MySQL。 **编辑:有人尝试过SwisSQL吗?这是一个迁移工具,但我不确定它是否能满足我的要求。 问题答案: 这是在脚本中标准化表的示例。我建议你做这样的事情 您将首先创