2017-09-25 34 views
0

我目前正在构建一个接口来构建问卷。问卷中的每个问题是存储在火力地堡结构如下:重新排序存储在Firebase中的动态集合/列表中的项目

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,覆盖现有的“问题”数据组。

这里是我的代码:

// Remove question action creator 
export function removeQuestion(key, questions) { 

    return (dispatch) => { 
    dispatch({type: REMOVE_QUESTION}); 

    const updatedQuestions = questions.filter((question) => { 
     return !(question.uid === key); // I remove the target item here. 
    }).map((question, index) => { 
     return { 
     lastModified: question.lastModified, 
     position: index, // I update the position of all other items here. 
     question: question.question, 
     stageId: question.stageId, 
     uid: question.uid 
     }; 
    }); 

    questionsRef.set(updatedQuestions) // And then I save the entire updated dataset here. 
    .then(() => dispatch(removeQuestionSuccess(key))) 
    .catch(error => dispatch(removeQuestionError(key, error))); 
    }; 
} 

但是,有没有这样做的更好的办法?

回答

1

这是我选择的解决方案。我所做的是:

  • 作为本地阵列(在我的终极版状态的情况下),将其存储为对象,从火力地堡拉,它,每当它需要转换为数组不再存储列表被突变。
  • 与阵列工作,除去规定的项目(I用于Array.Filter()此)
  • 地图过阵列,更新与他们的新位置的每个项(使用地图索引)
  • 推回之前
  • 解析阵列回对象到火力地堡

这是我写的,所以可能被应用到项目的任何列表的代码的通用版本:

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))); 
    }; 
} 
1

解决此问题的一种方法是使用浮点数来表示位置,而不是实际的序数整数。然后,当您需要重新排序时,不要重新保存所有不同的位置,只需在两个移动的项目之间取中点即可。

这样,当您删除一个项目时,您可以仅保留其他值,因为position是有序的,但不是有序的。

一个例子(项是字母,位置号码):

A: 1, B: 2, C: 3, D: 4 

-> move D between A and B 

A: 1, D: 1.5, B: 2, C: 3 

-> move C between D and B 

A: 1, D: 1.5, C: 1.75, B: 2 

-> remove D 

A: 1, C: 1.75, B: 2 
+0

这肯定会使保持位置更简单,以下项目重新定位或删除。感谢您的建议。 我以前见过这个,虽然不是使用浮点数,而是使用一个序数,而是使用100或10的数值(例如A:10,B:20,C:30)。 我现在看到浮点的优点是总是可以计算中点,相邻定位项之间的差异可以变得越来越小。但它有没有突破?我想这取决于你如何处理你的浮点精度? –

+1

这里有一些理论上的限制/重新排序的次数,它会中断,但它需要大量的最坏情况下的重排序(我认为)。如果达到某个阈值(例如,如果兄弟姐妹之间的距离小于等于0.00001),您可能需要进行某种“重置”操作,以重新排序它们。 –