I'm new at firebase/firestore. Appreciate your thoughts on this.
I'm trying to create an order form using Firestore.
I was wondering:
Do I need to create a YEAR, MONTH, DATE of collections and documents just to save all the order forms ?
This felt redundant to me, otherwise a lot of databases in Firestore will require a lot of collections and documents of dates!
E.g.:
(CAPS is Collection, bracketed are the documents)
YEAR (2018) -> MONTH (Jan, Feb, Mar, etc)
JAN -> 1 (order #1, order #2, order #3, etc)
JAN -> 2 (order #1, order #2, etc...)
Or just a simple time stamp on each document of order form - and then if I want to look up say for the month of January, is there a search query to look up all the documents in a specific month? or date?
And as order forms go, the user can enter as many items as possible. Is it correct to have each item stored as a new document? Therefore possibly creating 100+ documents per collection of order form.
E.g.:
order 1 collection - banana document, apple document, orange document
There is no single best data model. It all depends on the use-cases of your app. For a general introduction to this domain, I recommend reading NoSQL data modeling.
But in Firestore having a collection with many documents is not a concern. The database was made to scale to almost any number of documents.
You'll indeed want to store a timestamp in each order. The best way for this is like to use a server-side timestamp. You can then query for orders in a given date range with a query like this:
var now = new Date();
var yesterday = new Date(Date.now() - 24*60*60*1000);
ordersRef.where("timestamp", ">=", yesterday).where("timestamp", "<=", now)
Or
ordersRef.where("timestamp", ">=", "2017-01-01").where("timestamp", "<=", "2017-12-31")
For more examples, see the Firestore documentation on queries.
Related
I am building a calendar on IOS using Swift, with a Firestore back-end.
I am retrieving all the events for each day in a month at one time.
Currently I can only display events that start on a particular day.
This is no good if an event starts on a Friday night and ends on a Monday morning (think, weekend on holiday).
so...
I need to get all the Event documents from Firestore where the day currently being populated with events sits between the timestamps of the start and end fields on the Firestore document.
The obvious first choice is something like this:
db.collection("Event")
.whereField("user", isEqualTo: userID)
.whereField("start", isLessThanOrEqualTo: thisDate)
.whereField("end", isGreaterThanOrEqualTo: thisDate)
.getDocuments()
but it turns out Firebase won't let me run 2 inequality filters on different fields [:(
The only other option I can think of is to get all the events that started before today, scan through each one and check if it ended before today, then display the rest.
But this doesn't seem very efficient, especially if you think about 5 years down the line when a user might have an event for every day of the year (that's A LOT of documents to check through in a short space of time).
Does anybody have any suggestions as to how I might do this?
Thanks :)
UPDATE
I forgot to add this in, It's a screenshot of how the database is structured :)
(note that day, month, and year are obsolete fields now that I have started using timestamps)
Firestore has query limitations that allow inequality filters only on the same field:
In a compound query, range (<, <=, >, >=) and not equals (!=, not-in)
comparisons must all filter on the same field.
Unfortunately, it doesn't look like something that could be changed on the Google side because there were certain reasons for implementing the current design, for instance, the query speed.
In this case, you will need to use the solution that you've came up with in your code.
One solution we have used (not great but works) is time selectors. You need to add 'time selectors' to your model e.g.
const event = {
...baseEvent,
timeSelector: {
isoDay: 'yyyy-mm-dd',
isoWeek: 'kkkk-WW', // luxon format
isoMonth: 'yyyy-mm'
}
}
then depending on how wide your time interval is you can use array 'in' operator
db.collection("Event")
.where('timeSelector.isoWeek', 'in', ['1999-01', '1999-02'])
That will greatly reduce the amount of documents pulled client side, however an extra client side filtering will be required, and playing with time intervals is always fun
Are you able to use MongoDB to combine rows of data into one row?
I'm using dates with year, month, day and hour. The data is shown per hour. Is there a way to combine data of the hours into just one day with data. I would basically remove the hour column and sum the hour data into per day data.
I'm not sure what you mean by "the data is shown per hour" - do you mean it's stored in the database that way?
MongoDB doesn't have rows and columns - the equivalent of a row is a document, and the column equivalent is a field. Unlike in traditional SQL, a field isn't just one piece of information (a string, number/date, boolean, null, etc). It can be more than one piece of data - it can be an array, or a document, or an array of documents, etc.
Anyway, based on the small amount of information I have on your situation, I'd absolutely design the data with the bucket pattern. https://www.mongodb.com/blog/post/building-with-patterns-the-bucket-pattern
You could $unset the 'measurements' array and just keep the sum/count fields if that's what you want.
If your data is already set in stone, then I'd use an aggregation pipeline to group all the documents ('rows') together - the group _id would be year, month, day, and you could sum/count/min/max/etc the data in the group too.
How do I perform an equivalent of SQL extract/fetch records by month and year from a date in swift?
Two requirements are as follows:
List records by Month and Year
September 2015
October 2015
Display transactions falling under the Year and Month.
Edit: I do mean core data. Rephrased "equivalent in SQL" to equivalent of SQL" to clarify.
CoreData will store dates as doubles, which is the internal format for NSDate.
If you have a small database, just store the values as NSDate and filter based on that.
However, if you have a large database, you may want to denormalize your data a bit more.
You could store another field, say in "yyyymmdd" format, which gives you most of the filtering you require.
For finer grained control, you can also keep separate attributes for year, month, and day.
You may want to setup those fields as indexes as well, if you do lots of searching over vast amounts of data.
Remember, CoreData uses SQLite under the hood for most databases, but it's behavior characteristics are very different.
There is no universal "best" way, as it depends entirely on your data and how you use it.
My actual documents are more complex than this but simplifying them like so will explain the problem I want to solve. I have daily and weekly documents.
Daily Document: ObjectId, Type, Count, Date
Weekly Documents: ObjectId, Type, Count, StartDate, EndDate
If I wanted a daily report I can run a query that will select documents with Date field value between range X to Y and Type equal to 'daily'. I can do the same thing for Weekly reports and it all works.
The problem:
For weekly reports if the start date is not the first day of the week and the end date is not exactly the last day of the week, selecting documents with Type 'weekly' will produce inaccurate reports since weekly documents store the data for the entire week. This may seem strange but Google Analytics lets you do it:
In the above screenshot Jul 3rd isn't the beginning of that week, nor is Jul 17th the end of that week. But Google Analytics lets you see the data as you want.
Possible Solution:
One possible solution is to produce a daily report for the overflowing days and subtract it from the weekly report.
The question:
Is there a nicer solution to solving the problem I described? I'm open to redesigning the documents
For weekly reports if the start date is not the first day of the week
and the end date is not exactly the last day of the week, selecting
documents with Type 'weekly' will produce inaccurate reports since
weekly documents store the data for the entire week. This may seem
strange but Google Analytics lets you do it:
Because they don't store documents like that.
The way this works (I reckon) is that Google just summerises the daily documents and ignores your "week" range and applies their own range of saying:
get as many full weeks as possible and aggregate the daily documents that
come under that range
and then:
Just throw the others ontop making each the end and start point
I wouldn't try to mix week and daily documents here I would just query over daily documents only and aggregate client side.
In my application I have to store data month wise and year wise. So for this, I have to store the data along with date into database.
My requirement is how to store in terms of date and how to retrieve data with group by month and year. In my app I am showing a table of years and months, based on selected month and year. I have to show the data in a dashboard.
My problem is in storing and retrieving date data types.
Use the following syntax
SELECT * FROM DATABASE WHERE REQUIREDDATEFIELD LIKE '%2011-01%';
2011 is supposed to be the year
01 is supposed to be the month
DATABASE is supposed to be your mysql database name
REQUIREDDATEFIELD is supposed to be the field you are hoping to sort from month and year.
like '%2011-01%' is supposed to be meaning, all the records containing 2011-01 in the given field. It could be in the beginning or the end or in the middle of a large text, so having % in both the beginning and end of the search criteria is a good habit.
You just select either for a specific month or year or month and year. Or if you want all, you use GROUP BY.
I know this answer is quite vague and generic, but that's because your question is vague. You probably need to be more specific. Explain not only what you want to do, but what you have tried, and in which way that didn't work.