-
Notifications
You must be signed in to change notification settings - Fork 245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Firebase Notes (NoSQL Database) #82
Comments
This is an implementation example, with collections called "calendars" and "events" : import os
from dateutil.parser import parse as to_dt
from dateutil.tz import gettz as get_tz
from firebase_admin import credentials, initialize_app, firestore #, auth
from dotenv import load_dotenv
load_dotenv()
DEFAULT_FILEPATH = os.path.join(os.path.dirname(__file__), "..", "google-credentials.json")
CREDENTIALS_FILEPATH = os.getenv("GOOGLE_APPLICATION_CREDENTIALS", default=DEFAULT_FILEPATH)
class FirebaseService:
def __init__(self):
self.creds = credentials.Certificate(CREDENTIALS_FILEPATH)
self.app = initialize_app(self.creds) # or set FIREBASE_CONFIG variable and initialize without creds
self.db = firestore.client()
def fetch_authorized_calendars(self, email_address):
# see: https://firebase.google.com/docs/firestore/query-data/queries#query_operators
# ... https://firebase.google.com/docs/firestore/query-data/queries#query_limitations
# there is no logical OR query in firestore, so we have to fetch both and de-dup...
authorizedQuery = self.calendars_ref.where("authorizedUsers", "array_contains", email_address)
#adminQuery = self.calendars_ref.where("adminUsers", "array_contains", email_address)
#calendar_docs = list(authorizedQuery.stream()) + list(adminQuery.stream())
# but actually just add the admin into the authorized list for now
calendar_docs = list(authorizedQuery.stream())
# let's return the dictionaries, so these are serializable (and can be stored in the session)
calendars = []
for calendar_doc in calendar_docs:
calendar = calendar_doc.to_dict()
calendar["id"] = calendar_doc.id
calendars.append(calendar)
return calendars
@property
def calendars_ref(self):
"""Returns a (google.cloud.firestore_v1.collection.CollectionReference) """
return self.db.collection("calendars")
#def add_nested_events(self, events, calendar_id=None, calendar_ref=None):
# """
# Add event records to the given calendar document.
#
# Pass a calendar ref if possible, otherwise pass a calendar id and a new ref will be created.
#
# Params:
# calendar_ref (google.cloud.firestore_v1.document.DocumentReference) : the document reference object
#
# calendar_id (str) : the document id
#
# events (list of dict) : list of events to add, like [{
# "event_start": datetime.datetime object,
# "event_end": datetime.datetime object,
# "reservation": None
# }]
#
# Note: passing datetime objects gives us a timestamp object in firebase!
#
# Returns : (google.cloud.firestore_v1.types.write.WriteResult)
# """
# calendar_ref = calendar_ref or self.calendars_ref.document(calendar_id)
# return calendar_ref.update({"events": firestore.ArrayUnion(events)})
@property
def events_ref(self):
"""Returns a (google.cloud.firestore_v1.collection.CollectionReference) """
return self.db.collection("events")
def create_events(self, events):
"""
Creates new event documents from event data.
Params:
events (list of dict) : list of events to add, like [{
"calendar_id": (str), # referencing the calendar document id
"event_start": datetime.datetime object,
"event_end": datetime.datetime object,
"reservation": None
}]
Note: passing datetime objects gives us a timestamp object in firebase!
See: https://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes
"""
batch = self.db.batch()
for event_data in events:
event_ref = self.events_ref.document() # give each event its own unique id (so we can more easily look it up later!!)
batch.set(event_ref, event_data)
return batch.commit()
def fetch_daily_events(self, calendar_id, date, timezone="US/Eastern"):
"""Params: date (str) like '2021-01-01'"""
tz = get_tz(timezone)
day_start = to_dt(f"{date} 00:00").astimezone(tz)
day_end = to_dt(f"{date} 11:59").astimezone(tz)
query_ref = self.events_ref
query_ref = query_ref.where("calendar_id", "==", calendar_id)
query_ref = query_ref.where("event_start", ">=", day_start)
query_ref = query_ref.where("event_start", "<=", day_end)
event_docs = list(query_ref.stream()) #> list of DocSnapshot
events = []
for event_doc in event_docs:
event = event_doc.to_dict()
event["id"] = event_doc.id
event["event_start"] = event["event_start"].astimezone(tz) # otherwise this will show up as UTC in the browser.
event["event_end"] = event["event_end"].astimezone(tz) # otherwise this will show up as UTC in the browser
events.append(event)
return events
if __name__ == "__main__":
from pprint import pprint
service = FirebaseService()
print("CALENDARS...")
calendars_ref = service.db.collection("calendars")
calendars = [doc.to_dict() for doc in calendars_ref.stream()]
pprint(calendars) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
We already have some mongodb notes for basic NoSQL, but let's also add notes about firebase.
Setup
https://firebase.google.com/docs/firestore/quickstart
Usage
Something like this:
See: Managing Data - Firebase Python Docs
Also, for higher-level data modeling decisions (whether to store data in a nested document or in a separate collection), see videos like Data Modeling in Firebase.
https://firebase.google.com/docs/firestore/manage-data/structure-data
The text was updated successfully, but these errors were encountered: