2017-09-25 41 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),您可能需要進行某種「重置」操作,以重新排序它們。 –