Firestore: моделирование данных для приложения отслеживания объектов
Это мой первый проект Firestore и NoSQL, и я пытаюсь смоделировать свои данные.
У меня есть несколько объектов (порядка от 500 до 1000), которые физически путешествуют по всему земному шару. Они периодически (примерно раз в день) регистрируются, чтобы отправить свое геолокации вместе с некоторыми дополнительными данными.
Другими словами, существует тысяча потоков медленно накапливающихся данных отслеживания.
Как мне лучше структурировать мои данные для оптимизации по следующему запросу? Для каждого из тысячи объектов, дайте мне последние N мест отслеживания, отсортированные от самых новых до самых старых. Я предполагаю, что N будет около 100 до 300.
РЕДАКТИРОВАТЬ: Чтобы уточнить, это будет возвращать около 1000 х (от 100 до 300) отслеживания мест. Можно ли это сделать без 1000 запросов (т.е. по одному на каждый из объектов)?
1 ответ
Следующая структура базы данных должна работать для вашего варианта использования.
Firestore-root
|
--- drivers (collection)
| |
| --- driverId (document)
| |
| --- //other driver details
|
--- data (collection)
| |
| --- driverId (document)
| |
| --- driverData (collection)
| |
| --- driverDataId (document) //Same object as below
| |
| --- geoPoint: [[48.858376° N, 2.294537° E]]
| |
| --- date: Oct 11, 2018 at 6:16:58 PM UTC+3
| |
| --- driverId: "DriverUserId"
| |
| --- //other extra data
|
--- allData (collection)
|
--- driverDataId (document) //Same object as above
|
--- geoPoint: [[48.858376° N, 2.294537° E]]
|
--- date: Oct 11, 2018 at 6:16:58 PM UTC+3
|
--- driverId: "DriverUserId"
|
--- //other extra data
Они периодически (примерно раз в день) регистрируются, чтобы отправить свое геолокации вместе с некоторыми дополнительными данными.
Предполагая, что у вас есть класс модели для данных, которые драйвер отправляет один раз в день, объект, который должен быть отправлен в базу данных, должен быть отправлен в двух разных местах:
data (collection) -> driverId (document) -> driverData (collection) -> driverDataId (document)
а также
allData (collection) -> driverDataId (document)
Для всех объектов дайте мне последние N мест отслеживания, отсортированные от самых новых до самых старых.
Чтобы получить все эти объекты, нужен такой запрос:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference allDataRef = rootRef.collection("allData");
Query query = allDataRef.orderBy("date", Query.Direction.ASCENDING).limit(n);
Если вы хотите получить также информацию о драйвере, вам нужно сделать дополнительную get()
позвоните, чтобы вы могли получить его детали. Вы можете добиться этого, используя driverId
которые существуют как свойство в объекте данных драйвера.
Если вы хотите получить все эти объекты из одного драйвера, вы должны использовать следующий запрос:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference allDataRef = rootRef.collection("data").document(driverId).collecton("driverData");
Query query = allDataRef.orderBy("date", Query.Direction.ASCENDING).limit(n);
Эта практика называется denormalization
и это обычная практика, когда дело доходит до Firebase. Для лучшего понимания, я рекомендую вам посмотреть это видео, денормализация нормальна с базой данных Firebase. Это для базы данных реального времени Firebase, но тот же принцип применим к Cloud Firestore.
Кроме того, когда вы дублируете данные, нужно помнить одну вещь. Точно так же, как вы добавляете данные, вы должны поддерживать их. Другими словами, если вы хотите обновить / обнаружить элемент, вы должны делать это в каждом месте, где он существует.
Редактировать:
Согласно вашему комментарию, теперь я понимаю, что вы имеете в виду. В этом случае вы можете рассмотреть allData
коллекция фидов, в которую вы должны добавить, как видите, объекты данных драйвера. Скажем так n = 100
, Это означает, что каждый раз, когда вы добавляете новый объект после сотого объекта, вам нужно удалить самый старый. Так что это подразумевает дополнительную операцию удаления. Таким образом, вы будете хранить в этом фиде только 100 объектов определенного пользователя. И да, если у вас есть 1000 пользователей и у каждого пользователя есть 100 объектов данных, вам нужно будет запросить коллекцию, которая содержит 100 тыс. Документов. Поэтому, если вы хотите получить все эти данные одновременно, будет выполнено 100 000 операций чтения.
Edit2:
Есть еще одна схема, над которой я могу подумать, но это подразумевает некоторые тесты, потому что я не знаю, насколько большим может быть ваш объект данных драйвера. Поэтому, пожалуйста, смотрите мою схему ниже:
Firestore-root
|
--- drivers (collection)
|
--- driverId (document)
|
--- //other driver details
|
--- driverData (map)
|
--- driverDataId (document) //Same object as below
|
--- geoPoint: [[48.858376° N, 2.294537° E]]
|
--- date: Oct 11, 2018 at 6:16:58 PM UTC+3
|
--- driverId: "DriverUserId"
|
--- //other extra data
Как видите, я изменил driverData
сбор в map
внутри объекта драйвера. В этом случае вы также должны поддерживать эти 100 объектов на этой карте. В этом случае требуется только 1000 запросов, которые могут вернуть объект данных драйвера 100 КБ. Но обратите внимание, проблема в том, что документы имеют пределы. Таким образом, существуют некоторые ограничения в отношении объема данных, которые можно поместить в документ. Согласно официальной документации относительно использования и ограничений:
Максимальный размер документа: 1 МБ (1 048 576 байт).
Как видите, вы ограничены 1 МБ данных в одном документе. Когда мы говорим о хранении текста, вы можете хранить довольно много, но по мере увеличения вашей карты объектов будьте осторожны с этим ограничением.