I am very new to SPAs (Single Page Applications) and noSQL coding, but I am very interested in these topics!
I do have experience with PHP, mySQL & relational Databases which is messing with my mindset when developing with a noSQL database.
I am currently developing a webapp where i create a collection called 'campaigns'.
This collection has a subcollection called 'categories'.
Which has another subcollection called 'notes'.
The Firestore setup is like this:
Campaigns
campaign1
Categories
category1
Notes
note1
note2
campaign2
Categories
category1
Notes
note1
note2
At the moment when I want to display note1 I have to create the URL like this:
domain.com/campaigns/Wi8AyzYgpKCnTXvCL9SV/categories/XlsMW4a8YRoLC1t3NbWG/notes/wg5oGQIZ8EOSYdFVOIlB
This seems a bit overkill.
Is there a way to shorten it to something like this:
domain.com/notes/wg5oGQIZ8EOSYdFVOIlBm
I know this can be done in a relational database, but I don't know if it can be done with Firestore
One solution would be to have a flat notes root collection with all the notes documents which have a campaign and category fields.
This way you can directly extract the document id from an url like domain.com/notes/wg5oGQIZ8EOSYdFVOIlBm. If you want to query for a specific campaign or category or a specific campaign/category couple, you just use a where() query (or a combination of tho where()s).
In terms of performance it will make no difference compare to a sub-collection approach as described in your question: the execution time for a query depends on the number of docs returned by the query.
Related
I have a collection of user subscriptions to books that contain the userId and the bookId. I have a collection of Books, which each have a collection of chapters. Those chapters have timestamp fields. I need a list of all of the chapters that a user is subscribed to, in reverse chronological order, and I am really only going to be needing the most recent 10 most of the time, since it will be shown on a scrolling listview in Flutter.
Can this even be done on Firebase? I know that I can do a collectionGroup and order that, for the chapters, and I can filter that by up to ten values if I include the bookId in the chapter document. But is it really a 10 subscription limit for my users? More than that would need some sort of bizarre parallel queries, or something.
Here's what the database looks like:
I'm looking for the most simply designed database structure for a given day, food type, food name and food price.
The part that is giving me trouble is, I feel like, the food name and food price need to be "tied together".
The pictures below are what I have experimented with, but I feel like I am over engineering the structure.
I think you need to understand the firebase ideas of collections and document better - this two level structure is often confusing to developers more familiar with SQL-like databases.
A document contains fields and potentially collections. A collection is always a collection of documents.
So in your case you might make a collection called days which contains documents 'monday','tuesday'....
the monday document might contain some other fields (the chef, the date ect) and a collection (of documents) called 'dessert'
Then each of your dessert documents might include fields for description, price etc.
So in general if you are trying to define a list of multiple similar objects your are wanting a collection of documents. If you are wanting to define fields within an object you should be looking to store them in a document.
I have a book collection for example, each book has 'genre' field. How to query all books which genre is "fantasy" or "historical"? Like SQL SELECT * FROM book WHERE genre in ("fantasy", "historical"). Pretty usual SQL query as my opinion.
I found this feature request in GitHub, which isn't resolved yet. The Firestore documentation says: "Logical OR queries aren't supported". So, I cannot do such simple query in Firestore? What is a workaround? Should I query each genre separately and join the result?
Note, that I found similar questions like "How to get multiple documents by set of ids?", but not about custom properties. For ids, there is 'getAll()' method in the js admin sdk for example.
It is not supported in firestore as you correctly identified. You can send two separate queries and merge the results locally. This is how it needs to be done unfortunately. If yours is a simple usecase, sending two separate requests shouldn't be a problem.
However, have a look at rxfire package which is officially supported by firebase. Note that it doesn't support or queries per se but with the help of rxjs, it makes such tasks easier to manage. Here's an excerpt from the link below on what it can do:
Firebase provides realtime streams and async callbacks to do all sorts
of awesome things in your app. Getting data from one realtime stream
is easy enough, but what if you want to join it from another?
Combining multiple async streams of data can get complex. At Firebase,
we wanted to help simplify things, so we created a new JavaScript
library: RxFire.
Link to introductory blogpost: RxFire
I’m working with an angular 6 application that uses a firebase database. I’m wondering how to filter a list of documents for unique records according to a specific field and only the most recent ones.
For example, I have a collection of invitations that look like this:
{
name: ‘Joe Shmoe’,
email: ‘jshmoe#gmail.com'
InvitedOn: ‘Sat Nov 3 2018 12:00PM’
}
Each person can be invited multiple times, so the collection may contain several invitations for Joe Schmoe, but they will all have different dates/times for the InvitedOn property.
What I’d like to do is:
Group the documents by email.
For each group, sort by date invited.
Remove duplicate invites by taking the most recent one.
I’m not familiar enough with firebase to know how to do this. I’m working in angular 6 like I said, so I would very much appreciate if someone could explain how to do this in typescript/javascript, or direct me to a good site that explains it.
First prevent duplicates by testing (querying) the database for its existence. If it already exists, update what's already there vs writing a whole new record.
Firestore offers better compound query functionality than Firebase Realtime Database. Unless you have a reason not to, use Firestore.
Reading and Deleting (removing) are distinct from one another. Just because you read the most recent record does not mean that record is deleted from the database, you would have to delete it also (if that's what you want to do).
So, the answer is to switch over to Firestore, don't record duplicate data, and lastly, store your timestamps as Date.now() timestamps so you're working with simple number comparisons to search by.
It sounds like you want to show a list of email addresses with the latest date they were invited on. If that's what you need, I'd recommend modeling precisely that in your database. Assuming Cloud Firestore, it'd look something like:
emails_with_invites (collection)
jshmoe#gmail.com (document id)
lastInvitedOn: ‘Sat Nov 3 2018 12:00PM’
With a collection like this the email address is automatically unique (your "group by" requirement) and you automatically have the last invite date. The price for this, is that you'll have to update this additional collection whenever you write an invite. You can either do this in the app code itself, or using Cloud Functions.
I see that a CosmosDb can support both graph queries as well as more traditional SQL like queries - however I'm a bit confused about what kind of underlying schema is best at the collections level. If I were to model something in MongoDb or SQL Server, or Neo4j, I would have very different schemas. Also - it seems like I can query using more traditional SQL-like syntax - which makes it confusing about what's right or efficient underneath. Sometimes, making something easy to query does not mean that one should assume that it's an efficient query.
Is CosmosDb at it's heart a document database and I should model it accordingly - or is it a very different beast.
Example use case
Here's an example- let's say I have:
a user profile
multiple post types (photo, blog, question)
users can like photos
users can comment on photos, blogs, questions
With a sql database I would have tables:
profiles
photos
blogs
questions
and join tables with referential integrity to support the actions:
photoLikes
blogComments
photoComments
questionComments
With a graph database
I would just have the same core tables
profiles
photos
blogs
questions
and just create graph relationship types for like and comment - relying on the code business logic to enforce the rule that you can't like blogs, etc..
With a document db like MongoDb
Again, I might have the same core tables
profiles
photos
blogs
questions
Comments would be sub collections under each - and there would be a question of whether we want to keep the likes as an embedded collection under each profile, or under photos.. and we would have to increment and sync a like count to the other collection (depending on the use case we might create a like collection as well). Comments would be tucked under each photo, blog or question as an embedded collection and not have their own top-level collection.
So my question is this:
How do we model this schema in CosmosDB? Should we model it like a traditional Document Database like MongoDb, or does having access to a graph query allow us additional freedoms like not having to denormalize fields for actions such as "like?"
Azure Cosmos DB database engine is designed to be fully schema-agnostic.
A container (which can be a graph, a collection of documents, or a table) is a schema-agnostic container of arbitrary user generated content which gets automatically indexed upon ingest. I suggest to read "Schema-Agnostic Indexing with Azure DocumentDB" - http://www.vldb.org/pvldb/vol8/p1668-shukla.pdf, which is the same in Cosmos DB to better understand the details.
How do we model this schema in CosmosDB? Should we model it like a traditional Document Database like MongoDb, or does having access to a graph query allow us additional freedoms like not having to denormalize fields for actions such as "like?"
When you start modeling data in Azure Cosmos DB, you need to consider: 1.Is your application read heavy or write heavy? 2.How is your application going to query and update data? etc. Normally denormalized data models can provide better read performance, normalizing can provide better write performance.
This article explained with example how to model document data for NoSQL databases, and shared some scenarios for using embedded data models, normalized data models and Hybrid data models, which should be helpful.