Реализация приложения Android+Web(Angular)+Firebase, которое имеет отношение «многие ко многим»: Пользователь ‹-> Виджет (виджеты могут быть доступны нескольким пользователям).
Соображения:
- Список всех виджетов, которые есть у пользователя.
- Пользователь может видеть только те виджеты, которые ему предоставлены.
- Иметь возможность видеть всех пользователей, которым предоставлен доступ к данному виджету.
- Один виджет может принадлежать/администрироваться нескольким Пользователям с равными правами (изменить виджет и изменить, кому он будет предоставлен). Подобно тому, как Google Диск предоставляет доступ определенным пользователям.
Один из подходов к реализации выборки (стиль объединения) — это воспользоваться следующим советом: https://www.firebase.com/docs/android/guide/structuring-data.html («Joining Flattened Data
») через несколько прослушивателей. Однако у меня есть сомнения по поводу этого подхода, потому что я обнаружил, что загрузка данных будет тревожно медленной (по крайней мере, на Android) - я спросил об этом в другом вопросе - Firebase Android: медленное соединение с использованием многих слушателей, похоже, противоречит документации .
Итак, этот вопрос касается другого подхода: пользовательских копий всех виджетов, которые есть у пользователя. Как используется в руководстве Firebase+Udacity «ShoppingList++» ( https://www.firebase.com/blog/2015-12-07-udacity-course-firebase-essentials.html ).
Их структура выглядит следующим образом:
В частности эта часть - userLists
:
"userLists" : {
"abc@gmail,com" : {
"-KBt0MDWbvXFwNvZJXTj" : {
"listName" : "Test List 1 Rename 2",
"owner" : "xyz@gmail,com",
"timestampCreated" : {
"timestamp" : 1456950573084
},
"timestampLastChanged" : {
"timestamp" : 1457044229747
},
"timestampLastChangedReverse" : {
"timestamp" : -1457044229747
}
}
},
"xyz@gmail,com" : {
"-KBt0MDWbvXFwNvZJXTj" : {
"listName" : "Test List 1 Rename 2",
"owner" : "xyz@gmail,com",
"timestampCreated" : {
"timestamp" : 1456950573084
},
"timestampLastChanged" : {
"timestamp" : 1457044229747
},
"timestampLastChangedReverse" : {
"timestamp" : -1457044229747
}
},
"-KByb0imU7hFzWTK4eoM" : {
"listName" : "List2",
"owner" : "xyz@gmail,com",
"timestampCreated" : {
"timestamp" : 1457044332539
},
"timestampLastChanged" : {
"timestamp" : 1457044332539
},
"timestampLastChangedReverse" : {
"timestamp" : -1457044332539
}
}
}
},
Как видите, информация о копиях списка покупок "Test List 1 Rename 2"
появляется в двух местах (для 2 пользователей).
А вот остальное для полноты:
{
"ownerMappings" : {
"-KBt0MDWbvXFwNvZJXTj" : "xyz@gmail,com",
"-KByb0imU7hFzWTK4eoM" : "xyz@gmail,com"
},
"sharedWith" : {
"-KBt0MDWbvXFwNvZJXTj" : {
"abc@gmail,com" : {
"email" : "abc@gmail,com",
"hasLoggedInWithPassword" : false,
"name" : "Agenda TEST",
"timestampJoined" : {
"timestamp" : 1456950523145
}
}
}
},
"shoppingListItems" : {
"-KBt0MDWbvXFwNvZJXTj" : {
"-KBt0heZh-YDWIZNV7xs" : {
"bought" : false,
"itemName" : "item",
"owner" : "xyz@gmail,com"
}
}
},
"uidMappings" : {
"google:112894577549422030859" : "abc@gmail,com",
"google:117151367009479509658" : "xyz@gmail,com"
},
"userFriends" : {
"xyz@gmail,com" : {
"abc@gmail,com" : {
"email" : "abc@gmail,com",
"hasLoggedInWithPassword" : false,
"name" : "Agenda TEST",
"timestampJoined" : {
"timestamp" : 1456950523145
}
}
}
},
"users" : {
"abc@gmail,com" : {
"email" : "abc@gmail,com",
"hasLoggedInWithPassword" : false,
"name" : "Agenda TEST",
"timestampJoined" : {
"timestamp" : 1456950523145
}
},
"xyz@gmail,com" : {
"email" : "xyz@gmail,com",
"hasLoggedInWithPassword" : false,
"name" : "Karol Depka",
"timestampJoined" : {
"timestamp" : 1456952940258
}
}
}
}
Однако, прежде чем я приступлю к реализации подобной структуры в своем приложении, я хотел бы развеять некоторые сомнения.
Вот мои взаимосвязанные вопросы:
- В своем приложении ShoppingList++ они допускают только одного «владельца», назначенного в узле
ownerMappings
. Таким образом, никто другой не может переименовать список покупок. Я хотел бы иметь несколько "владельцев"/админов с равными правами. Будет ли такая структура сохранения копий для каждого пользователя по-прежнему работать для нескольких пользователей-владельцев/администраторов без риска повреждения данных/«десинхронизации» или «шуток»? - Может ли повреждение данных произойти в таких сценариях: User1 отключается, переименовывает Widget1 в Widget1Prim. Пока пользователь 1 находится в автономном режиме, пользователь 2 предоставляет доступ к виджету 1 пользователю 3 (копия пользователя 3 еще не будет знать о переименовании). Пользователь 1 выходит в сеть и отправляет информацию о переименовании Виджета 1 (только своей копии и копии Пользователя 2, о чем клиентский код знал на момент переименования, не обновляя копию Пользователя 3). Теперь в наивной реализации User3 будет иметь старое имя, а остальные будут иметь новое имя. Вероятно, это будет редко, но все же немного беспокоит.
- Мог ли/должен ли быть сценарий повреждения данных в пункте «2». решить с помощью некоторого процесса (например, в AppEngine), прослушивающего изменения и обеспечивающего надлежащее распространение на все пользовательские копии?
- И/или может/должен быть сценарий повреждения данных в пункте «2». решить путем реализации избыточного прослушивания как изменений общего доступа, так и переименования, а также распространения изменений на копии для каждого пользователя, чтобы справиться с особым случаем? В большинстве случаев в этом нет необходимости, поэтому это может привести к снижению производительности/пропускной способности и усложнению кода. Стоит ли оно того?
- В дальнейшем, когда у нас будет несколько версий, развернутых «в дикой природе», не станет ли разработка схемы громоздкой, учитывая, какая часть ответственности за обработку данных лежит на коде в клиентах? Например, если мы добавим новую связь, о которой старые версии клиента еще не знают, не кажется ли она хрупкой? Затем вернитесь к серверному процессу syncer-ensurerer, например. AppEngine (описано в вопросе «3.»)?
- Не кажется ли вам хорошей идеей также иметь «основную справочную копию» каждого виджета/списка покупок, чтобы предоставить хороший «источник правды» для любых операций типа синхронизатора-гаранта, которые будут обновлять копии для каждого пользователя. ?
- Какие-либо особые соображения/ловушки/блокировщики в отношении разрешений rules.json/rules.bolt для данных, структурированных таким (избыточным) образом?
PS: Я знаю об атомарных многопутевых обновлениях через updateChildren()
- обязательно воспользуюсь ими.
Любые другие подсказки/наблюдения приветствуются. ТИА.