Reputation: 33
Recently I've been playing around with Geohashes and Firestore. My todo scenario is to have a collection of documents (restaurants) and each restaurant will have list of Geohashes which delivers to.
I want to avoid adding the geoashes in the document restaurant as the document can be many times bigger than it should be.
The initial idea is to have all of the geohashes in a subcollection of the restaurant document but I found out its not possible to perform queries in subcollection of documents.
The second idea was to extract the geohashes to top level in a collection of delivery areas.
document:{ restaurantName: "aRestaurant",
deliveryArea: Arraylist<String> }
The problem in this scenario is that I will get back a list of restaurant names, where then I need to query the restaurants collection to get them and as far as I know I cannot perform OR operations in the queries.
It is my first time playing around with document databases and Firestore. Any guidance will be much appreciated.
Upvotes: 3
Views: 4492
Reputation: 599541
firebaser here
Our original GeoFire library for the Firebase Realtime Database solved precisely this problem by having a separate top-level node for the geohashes. Each key under that node would typically correspond to the key of an actual entity in another top-level node.
So something like:
locations
key1: { g: "sa7ads", l: [ 14.5232, -156.17843 ] },
key2: { g: "fds347", l: [ -127.172, 167.1324 ] }
restaurants
key1: { name: "This is the first restaurant", ... },
key2: { name: "This is the second restaurant", ... },
With this structure, you perform a geoquery on /locations
and then read the additional information of each restaurant in range from /restaurants/$key
. That scaled quite well.
I'd recommend the same approach with Cloud Firestore. You'd have two top-level collections: one with the (smaller) location data, and one with the (bigger) additional data about each restaurant. This reduces the amount of data you read, although you will end up reading more documents. You'll have to balance these two (bandwidth vs. document reads) off against each other.
A few months ago I gave a talk about performing geoqueries on Cloud Firestore that might be worth checking out.
Upvotes: 1
Reputation: 138944
I want to avoid adding the geoashes in the document restaurant as the document can be many times bigger than it should be.
Yes, don't do that because documents have limits. So there are some limits when it comes to how much data you can put into a document. According to the official documentation regarding usage and limits:
Maximum size for a document: 1 MiB (1,048,576 bytes)
As you can see, you are limited to 1 MiB total of data in a single document. When we are talking about storing text, you can store pretty much but if you are using complex objects, this is not an option.
The initial idea is to have all of the geohashes in a subcollection of the restaurant document but I found out its not possible to perform queries in subcollection of documents.
It's is a good solution. Your database structure should look like this:
Firestore-root
|
--- restaurants (collection)
|
--- restaurantId (document)
|
--- geohashes (collection)
|
--- geohashId (document)
|
--- //details about the location
So a query that can allow you get all geohash
objects of a particular restaurant, will work perfectly fine.
The second idea was to extract the geohashes to top level in a collection of delivery areas
Is not a bad solution, but you should create an extra get()
call, to get restaurant details but even if do this, is not a bad call, there is no problem regarding nested queries in Firestore. There is no need for OR
operation.
Edit: According to your comment, yes, you're right, you cannot query the database to get back restaurant objects but we have here a work around too. In this case you should consider augmenting your data structure to allow a reverse lookup, by addining an new collection like this:
Firestore-root
|
--- geohashes (collection)
|
--- geohashId (document)
|
--- geohashRestaurants (collection)
|
--- restaurantId
|
--- //restaurant details
This tehnique is called denormalization
which as you can see implies duplicating data. But you need to know that there is no problem with duplicating data, when it comes to Firebase. This is a quite common practice and for that, I recommend you see this video, Denormalization is normal with the Firebase Database. Is for Firebase realtime database but same principle apply to Cloud Firestore as well.
When you are duplicating data, there is one thing that need to keep in mind. In the same way you are adding data, you need to maintain it. With other words, if you want to update/detele an item, you need to do it in every place that it exists.
Upvotes: 0