重新排序Firebase中存储的动态集合/列表中的项目
我目前正在制作一个界面来构建一份调查问卷。问卷中的每个问题都存储在Firebase中,其结构如下:重新排序Firebase中存储的动态集合/列表中的项目,firebase,react-redux,Firebase,React Redux,我目前正在制作一个界面来构建一份调查问卷。问卷中的每个问题都存储在Firebase中,其结构如下: questions | - {key} | - lastModified // <-- When the question was created, last updated | - position // <-- The position in which the question appears on frontend |
questions
| - {key}
| - lastModified // <-- When the question was created, last updated
| - position // <-- The position in which the question appears on frontend
| - question // <-- Question text content
| - uid // <-- The unique key with which it is saved to firebase
/* ... */
/* Repeat for n questions! */
/* ... */
但是,有更好的方法吗?解决这个问题的一种方法是使用浮点数来表示位置,而不是实际的序数整数。然后,当您需要重新订购时,而不是重新保存所有不同的位置,只需在移动的两个项目之间取中点即可 这样,当您删除一个项目时,您可以只保留其他值,因为
位置
是有序的,而不是有序的
示例(项目为字母,位置为数字):
解决这个问题的一种方法是使用浮点数来表示位置,而不是实际的序数整数。然后,当您需要重新订购时,而不是重新保存所有不同的位置,只需在移动的两个项目之间取中点即可 这样,当您删除一个项目时,您可以只保留其他值,因为
位置
是有序的,而不是有序的
示例(项目为字母,位置为数字):
这就是我选择的解决方案。我所做的是:
- 不再在本地将列表存储为数组(在我的Redux状态中),将其存储为从Firebase提取的对象,在需要修改时将其转换为数组
- 使用数组时,删除指定的项(我用于此)
- 映射到数组,使用每个项目的新位置更新它们(使用映射索引)
- 在将数组推回Firebase之前,将其解析回对象
这是我编写的代码的通用版本,因此可以应用于任何项目列表:
export function removeItem(key, items) {
return (dispatch) => {
dispatch({type: REMOVE_ITEM});
// Convert items object (from state) into an array for easier manipulation
const itemsArr = items ? Object.keys(items).map(key => items[key]) : [];
const updatedItems = itemsArr.filter((item) => {
// Filter out the item that needs to be removed
return !(item.uid === key);
}).map((item, index) => {
// Update new position for remaining items
return {
lastModified: item.lastModified,
position: index,
content: item.content,
uid: item.uid
};
});
// Parsing array back into obj before pushing to Firebase
let updatedItemsObj = {};
updatedItems.forEach(item => {
updatedItemsObj[item.uid] = item;
});
itemsRef.set(updatedItemsObj)
.then(() => dispatch(nextAction(...)))
.catch(error => dispatch(errorAction(key, error)));
};
}
这就是我选择的解决方案。我所做的是:
- 不再在本地将列表存储为数组(在我的Redux状态中),将其存储为从Firebase提取的对象,在需要修改时将其转换为数组
- 使用数组时,删除指定的项(我用于此)
- 映射到数组,使用每个项目的新位置更新它们(使用映射索引)
- 在将数组推回Firebase之前,将其解析回对象
这是我编写的代码的通用版本,因此可以应用于任何项目列表:
export function removeItem(key, items) {
return (dispatch) => {
dispatch({type: REMOVE_ITEM});
// Convert items object (from state) into an array for easier manipulation
const itemsArr = items ? Object.keys(items).map(key => items[key]) : [];
const updatedItems = itemsArr.filter((item) => {
// Filter out the item that needs to be removed
return !(item.uid === key);
}).map((item, index) => {
// Update new position for remaining items
return {
lastModified: item.lastModified,
position: index,
content: item.content,
uid: item.uid
};
});
// Parsing array back into obj before pushing to Firebase
let updatedItemsObj = {};
updatedItems.forEach(item => {
updatedItemsObj[item.uid] = item;
});
itemsRef.set(updatedItemsObj)
.then(() => dispatch(nextAction(...)))
.catch(error => dispatch(errorAction(key, error)));
};
}
这当然会使物品重新定位或移除后的位置保持更简单。谢谢你的建议。我以前见过这种情况,虽然没有使用浮点数,而是使用序数,但数量级为100或10(例如A:10、B:20、C:30)。我现在明白了,浮动的优点是,中点总是可以计算的,相邻定位项目之间的差异可以变得越来越小。但它曾经破裂过吗?我想这取决于你是如何处理浮点精度的?理论上会有一些限制/重新排序的次数,但这需要大量最坏情况下的重新排序才能做到(我认为)。如果达到某个阈值(例如,如果兄弟姐妹相距<0.00001或其他什么),您可以进行某种“重置”,使其重新排序。这当然会使在项目重新定位或移除后保持位置更简单。谢谢你的建议。我以前见过这种情况,虽然没有使用浮点数,而是使用序数,但数量级为100或10(例如A:10、B:20、C:30)。我现在明白了,浮动的优点是,中点总是可以计算的,相邻定位项目之间的差异可以变得越来越小。但它曾经破裂过吗?我想这取决于你是如何处理浮点精度的?理论上会有一些限制/重新排序的次数,但这需要大量最坏情况下的重新排序才能做到(我认为)。如果达到某个阈值(例如,如果兄弟姐妹之间的距离小于0.00001或其他情况),您可以进行某种“重置”,以重新调整它们。
export function removeItem(key, items) {
return (dispatch) => {
dispatch({type: REMOVE_ITEM});
// Convert items object (from state) into an array for easier manipulation
const itemsArr = items ? Object.keys(items).map(key => items[key]) : [];
const updatedItems = itemsArr.filter((item) => {
// Filter out the item that needs to be removed
return !(item.uid === key);
}).map((item, index) => {
// Update new position for remaining items
return {
lastModified: item.lastModified,
position: index,
content: item.content,
uid: item.uid
};
});
// Parsing array back into obj before pushing to Firebase
let updatedItemsObj = {};
updatedItems.forEach(item => {
updatedItemsObj[item.uid] = item;
});
itemsRef.set(updatedItemsObj)
.then(() => dispatch(nextAction(...)))
.catch(error => dispatch(errorAction(key, error)));
};
}