我有一个这样的清单:
{
randomFirebaseGeneratedUID: {position: 0, someData: ''},
randomFirebaseGeneratedUID: {position: 1, someData: ''},
randomFirebaseGeneratedUID: {position: 2, someData: ''},
randomFirebaseGeneratedUID: {position: 3, someData: ''},
randomFirebaseGeneratedUID: {position: 4, someData: ''},
}
现在我想添加一个新项目,例如,在位置1和2之间
我很难找到一个干净,正确的方法。我现在想出的是:
export const addAtListPositionHelper = (list, payload) => {
Object.keys(list)
.filter(key => list[key].position > payload.position)
.forEach(key => {
list[key].position = list[key].position + 1
})
list.push().set(payload)
return list
}
export function addAtListPosition(contentId, payload) {
const db = getFirebaseInstance().database()
db.ref(`${contentId}`).transaction(list => addAtListPositionHelper(list, payload))
}
有效负载看起来像:{p: 2, someData: ''}
这个问题是我不能按照代码中的内容来推送有效负载,因为列表实际上是一个对象,这些对象的id是从firebase生成的UID。
当然我可以自己生成UID,但是对我来说看起来有些麻烦,因为我有一些由firebase生成的UID和一些由我自己生成的UID。
我想到的另一种方法是先推送项目然后再进行排序,但这可能会导致短时间内数据不一致。
是否真的没有更好的方法来处理我认为非常常见的用例?
答案 0 :(得分:0)
这听起来很混乱,现在正处于竞争状态。对任何数据库进行重新索引都是一项昂贵的操作,尤其是Firebase,因为它具有NoSQL / Realtime特性。
我能够快速想到的唯一方法是在整个列表中使用事务。这将起作用,但会严重损害此代码的可伸缩性。
问题源于这样一个事实,即你希望你的位置是连续的整数,这是难以扩展的。实际上,最古老的Firebase博客文章之一就是建议的:Best Practices: Arrays in Firebase。
因此,为了使此操作更具可伸缩性,您必须远离作为顺序整数的位置。我知道两种方法:
使它们成为非连续的
将它们设为非整数
: - )
另一种方法是在生成新文档时留出插入项目的空间。例如。如果你将索引分开如下:
{
randomFirebaseGeneratedUID: {position: 0, someData: ''},
randomFirebaseGeneratedUID: {position: 10, someData: ''},
randomFirebaseGeneratedUID: {position: 20, someData: ''},
randomFirebaseGeneratedUID: {position: 30, someData: ''},
randomFirebaseGeneratedUID: {position: 40, someData: ''},
}
然后10到20之间的项目可以获得位置15.这实际上很常见,并且大大减少了重新索引所有项目的需要。
如果您的头寸可以是非整数,您将永远不必重新索引。然后在1和2之间插入一个简单的1.5。并且通过浮点数的分辨率,您很快就不会用尽“位置”。
这实际上是我最近需要移动/重新排序/插入文档时采用的方法。