Список задач с функцией повторного заказа с использованием Firebase / Firestore - PullRequest
3 голосов
/ 09 апреля 2019

Я хочу составить список задач, которые могут изменить их порядок, но я не уверен, как сохранить это в базе данных.

Я не хочу использовать массив, потому что я должен сделать некоторыедальнейшие запросы в будущем.

Вот скриншот моей базы данных:

Database screenshot

Я пытаюсь сделать что-то вроде Trello, гдепользователь добавляет задачи и может перемещать задачи вверх и вниз в соответствии с их приоритетом.Мне нужно изменить положение задач в базе данных, а также для ведения записи.Я не могу понять, как это сделать в любой базе данных.Я опытный разработчик, и я работал с mongodb и firebase, но для меня это нечто уникальное.

Вот код для создания и получения всех задач.Когда я пытаюсь переместить какую-то задачу в коллекцию.Я поддерживал индекс в каждой задаче.Скажем, когда я перемещаю задачу из позиции индекса 5 в индекс 2, мне нужно отредактировать все предстоящие индексы на +1, есть ли лучший подход?

Пример кода

class taskManager {
    static let shared = taskManager()
    typealias TasksCompletion = (_ tasks:[Task],_ error:String?)->Void
    typealias SucessCompletion = (_ error:String?)->Void

    func addTask(task:Task,completion:@escaping SucessCompletion){
        Firestore.firestore().collection("tasks").addDocument(data: task.toDic) { (err) in
            if err != nil {
                print(err?.localizedDescription as Any)
            }
            completion(nil)
        }
    }

    func getAllTask(completion:@escaping TasksCompletion){
        Firestore.firestore().collection("tasks")
            .addSnapshotListener { taskSnap, error in
                taskSnap?.documentChanges.forEach({ (task) in
                    let object = task.document.data()
                    let json = try! JSONSerialization.data(withJSONObject: object, options: .prettyPrinted)
                    var taskData = try! JSONDecoder().decode(Task.self, from: json)
                    taskData.id = task.document.documentID

                    if (task.type == .added) {
                        Task.shared.append(taskData)
                    }
                    if (task.type == .modified) {
                        let index = Task.shared.firstIndex(where: { $0.id ==  taskData.id})!
                        Task.shared[index] = taskData
                    }
                })
                if error == nil{
                    completion(Task.shared,nil)
                }else{
                    completion([],error?.localizedDescription)
                }
            }
    }
}

Ответы [ 2 ]

2 голосов
/ 10 апреля 2019

Я думаю, что вопрос, который вы пытаетесь задать, это больше о дизайне базы данных .

Когда вы хотите иметь возможность поддерживать порядок с группой предметов, имея возможностьЧтобы изменить их порядок, вам понадобится столбец, чтобы сохранить порядок.

Вы столкнетесь с проблемой, когда попытаетесь заказать их, если они заказаны последовательно.

Пример

Например, если вы хотите переместить Item1 за Item4:

До

Элемент с индексом заказа.

 1. Item1, order: 1
 2. Item2, order: 2
 3. Item3, order: 3
 4. Item4, order: 4
 5. Item5, order: 5
 6. Item6, order: 6

После

Проблема : нам приходилось обновлять каждую запись между перемещаемым элементом и местом его размещения.

Почему этоэто проблема : это Большой O (n) - для каждого перемещаемого пространства мы должны обновить столько записей.По мере того, как вы получаете больше задач, это становится все более серьезной проблемой, так как это займет больше времени и будет плохо масштабироваться.Было бы неплохо иметь Большой O (1), где у нас есть постоянное количество изменений или как можно меньше.

 1. Item2, order: 1 - Updated
 2. Item3, order: 2 - Updated
 3. Item4, order: 3 - Updated
 4. Item1, order: 4 - Updated
 5. Item5, order: 5
 6. Item6, order: 6

Возможное решение № 1 (ОК, может быть?) - Интервал

Вы можете попытаться придумать хитрый метод, в котором вы попытаетесь разместить номера заказов так, чтобы у вас были дыры, которые можно заполнить, не обновляя несколько записей.

Хотя это может быть сложно, и вы можетеПодумайте: «Почему бы не хранить Item1 в заказе: 4.5?» Я добавил связанный вопрос ниже, который подходит к этой идее и почему вам следует ее избегать.

Возможно, вы сможете проверить безопасностьсо стороны клиента заказа и избегайте попадания в базу данных для определения нового идентификатора заказа перемещения.

Это также имеет ограничения, так как вам, возможно, придется сбалансировать интервал или, возможно, у вас закончились числа к элементам.Возможно, вам придется проверить наличие конфликта, и при возникновении конфликта вы выполняете перебалансировку всего или рекурсивно проверяете элементы вокруг конфликта, следя за тем, чтобы другие обновления балансировки не вызывали больше конфликтов и чтобы разрешались дополнительные конфликты.

 1. Item2, order: 200
 2. Item3, order: 300
 3. Item4, order: 400
 4. Item1, order: 450 - Updated
 5. Item5, order: 500
 6. Item6, order: 600

Возможное решение № 2 (лучше) - Связанные списки

Как упомянуто в связанной ссылке ниже , вы можете использовать структуру данных, такую ​​как связанный список.Это сохраняет постоянное количество изменений для обновления, так что это Big O (1).Я немного перейду к связанному списку, если вы еще не поработали со структурой данных.

Как вы можете видеть ниже, для этого изменения потребовалось только 3 обновления, я считаю, что максимальное значение будет 5, как показано вExpected Updates.Вы можете подумать: «Ну, это заняло столько же с первой оригинальной проблемой / примером!»Дело в том, что это всегда будет максимум 5 обновлений по сравнению с тысячами или миллионами при первоначальном подходе [Big O (n)].

 1. Item2, previous: null, next: Item3 - Updated // previous is now null
 2. Item3, previous: Item2, next: Item4
 3. Item4, previous: Item3, next: Item1 - Updated // next is now Item1
 4. Item1, previous: Item4, next: Item5 - Updated // previous & next updated
 5. Item5, previous: Item1, next: Item4 - Updated // previous is now Item1
 6. Item6, previous: Item6, next: null

Ожидаемые обновления

  1. Элемент перемещается (предыдущий, следующий)
  2. Старый предыдущий элемент следующий
  3. Старый следующий элемент предыдущего
  4. Новый предыдущий элемент следующий
  5. Новый следующий элементпредыдущий

Связанные списки

Полагаю, я использовал double linked list.Вы, вероятно, могли бы избежать использования только одного связанного списка, у которого нет атрибута previous и только next.

Идея связанного списка состоит в том, чтобы думать о нем как о цепочке.ссылка, когда вы хотите переместить один элемент, вы должны отделить его от ссылки перед ним и позади нее, а затем связать эти ссылки вместе.Затем вы откроете место, где вы хотите разместить его, теперь у него будут новые ссылки с каждой стороны, и для этих новых ссылок они теперь будут связаны с новой ссылкой, а не друг с другом.

Возможное решение № 3 - Хранение документов / Json / Array

Вы сказали, что хотите держаться подальше от массивов, но вы можете использовать хранилище документов.Вы все еще можете иметь доступную для поиска таблицу элементов, и тогда каждая коллекция элементов будет иметь только массив идентификаторов / ссылок элементов.

Таблица элементов

 - Item1, id: 1
 - Item2, id: 2
 - Item3, id: 3
 - Item4, id: 4
 - Item5, id: 5
 - Item6, id: 6

Коллекция элементов

 [2, 3, 4, 1, 5, 6]

Похожие вопросы

Ресурсы для Big O

Другие вопросы

Дизайн вашей базы данных будет зависеть от того, чего вы пытаетесь достичь.Могут ли элементы принадлежать нескольким доскам или пользователям?

Можете ли вы переложить некоторые заказы на клиентскую сторону и позволить ему сообщить серверу, каков новый заказ?Вы все равно должны избегать неэффективных алгоритмов упорядочения на стороне клиента, но вы можете заставить их выполнять некоторую грязную работу, если вы им доверяете и не испытываете никаких проблем с целостностью данных, если несколько человек работают над одними и теми же элементами одновременно.время (это другие проблемы проектирования, которые могут или не могут быть связаны с БД, в зависимости от того, как вы их обрабатываете.)

1 голос
/ 09 апреля 2019

Есть несколько подходов, которые вы могли бы использовать для достижения такой функциональности:

Подход № 1:


вы можете задавать удаленную позицию вашей задачи вместо непрерывной позиции, что-то вроде этого:

Дата: 10 апреля 2019 г. Имя: «какое-то имя задачи» Индекс: 10 ... Индекс: 20 ... Индекс: 30

Здесь всего 3 задачи с позициями 10, 20,30. Теперь предположим, что вы хотите переместить третье задание в середину, просто измените позицию на 15, теперь у вас есть три задания с позициями 10, 15, 20, я уверен, что вы можете сортировать по позиции при получении всех заданий избазы данных, и я также предполагаю, что вы можете получить позиции задач, потому что пользователь будет переупорядочивать задачи в мобильном приложении или веб-приложении, чтобы вы могли легко получить позиции окружающих задач и вычислить среднюю позицию окружающих задач. Теперь давайтескажем, вы хотели переместить первое задание (которое теперь имеет индекс возможности 10) в середину, просто получите позиции окружающих заданий, которое составляет 15и 20 и вычислите середину, которая равна 17,5 ((20-15) /2=17,5), и вот, теперь у вас есть позиции 15, 17,5, 20

Кто-то сказал, что бесконечность между 1 и 2 такЯ думаю, что вы не собираетесь использовать наши числа, но все же вы думаете, что скоро закончится разделение, вы можете увеличить разницу и сделать ее 100000 ... 00 вместо 10

Подход# 2:


Вы можете сохранить все свои задачи в одном документе вместо отдельного документа в многослойной форме json, что-то вроде этого:

Задачи: '[{name: "какое-то имя ", дата:" какая-то дата "}, {имя:" какое-то имя ", дата:" какая-то дата "}, {имя:" какое-то имя ", дата:" какая-то дата "}] '

выполнив это, вы получите все задачи сразу на экране и проанализируете json как локальный массив. Когда пользователь переставит задачу, вы просто локально измените положение этого элемента массива и сохраните стратифицированную версию задач в базе данных.также есть некоторые недостатки этого подхода, если вы используетеПри разбиении на страницы это может быть трудно сделать, но, надеюсь, вы не будете использовать нумерацию страниц в приложении для управления задачами, и вы, вероятно, хотели бы показать все задачи на экране одновременно, как это делает Trello

...