使用child_added
,child_changed
和child_removed
听众将两个或多个Firebase表连接在一起是否可行?
例如,假设您有两个表。一个包含有关用户的基本信息,另一个包含用户与角色的关系。
用户
{
"1":
{
"forename": "Joe",
"surname": "Bloggs"
},
"2":
{
"forename": "Jane",
"surname": "Doe"
},
"3":
{
"forename": "Luke",
"surname": "Skywalker"
}
}
用户 - 角色关系
{
"a":
{
"userId": 1,
"roleId": 2
},
"b":
{
"userId": 2,
"roleId": 2
},
"c":
{
"userId": 3,
"roleId": 4
}
}
加入
如果您想要检索角色为2
的所有用户,则可以使用orderByChild
和equalTo
使用roleId
编写正常的Firebase查询。对于每个child_added
,您可以使用child_added
为每个相关用户收听orderByChild
。然后,两个文档中的值可以汇总到您的应用程序使用的单个对象中。它看起来可能如下所示。
代码
function join(initial, joins, callback)
{
const result = [];
initial.query.on
(
'child_added',
function(initialSnapshot)
{
const initialChild = initialSnapshot.val();
let initialResult = initialChild;
const resultIndex = result.push(initialResult) - 1;
joins.forEach
(
function(join)
{
const delay = Math.floor(resultIndex / LISTENER_BATCH_LENGTH);
setTimeout
(
function()
{
join.query(initialChild);
let joinResultPrevious = null;
const addedCallback = joinQuery.on
(
'child_added',
function(joinSnapshot)
{
const joinChild = joinSnapshot.val();
const joinResult = joinChild;
joinResultPrevious = joinResult;
initialResult = Object.assign(initialResult, joinResult);
callback(result);
}
);
joinQuery.on
(
'child_changed',
function(joinSnapshot)
{
const joinChild = joinSnapshot.val();
const joinResult = joinChild;
const deletedProperties = getMissingProperties(joinResult, joinResultPrevious);
deletedProperties.forEach
(
function(property)
{
delete initialResult[property];
}
);
initialResult = Object.assign(initialResult, joinResult);
joinResultPrevious = joinResult;
callback(result);
}
);
joinQuery.on
(
'child_removed',
function()
{
result.splice(resultIndex, 1);
callback(result);
}
);
},
delay
);
);
}
);
};
性能
麻烦的是,我已经尝试过这个功能,虽然它有效,但它的工作速度非常慢。我测试了大约2,100个用户文档及其相应的用户角色关系文档。使用Chrome的分析工具,大部分CPU时间似乎花费在Firebase的某些部分上。我不知道这是哪个部分,因为函数名称似乎被混淆了,其中一个昂贵的函数被标记为Qa
。或许浏览器根本无法做到这么多工作。但是,我确实想知道Firebase是否会产生数千个独立请求,而将它们组合在一起可能要便宜得多。无论哪种方式,考虑到明显的性能问题,了解以这种方式连接表是否可行将是有用的。
更新
我似乎在很大程度上解决了性能问题。它们似乎源于Firebase以某种方式锁定了浏览器线程。为加入侦听器引入一个带有setTimeout
的批量延迟似乎可以释放对其他进程的控制,包括DOM,它可以提供更平滑,更快速的用户体验。