I have a DB with a list of days ('Day' objects).
Each day has a list of events (one-to-many)
How do I write a fetch predicate in order to fetch all day objects where name=='Monday' and only include the events where the time is > aStartTime and time < aEndTime?
Or in other words....
I want an array of 'Monday' objects where day.events only contains the events for a certain time interval.
You can't without adding new Day objects; it goes against the whole point of Core Data (object graph/change management). And if each event can only have one Day, it gets messy.
Alternatively, you can return some sort of "proxy" Day objects, but that won't quite do the same thing (it might be closer to what you're looking for, though).
Alternatively, in each event, store a number between 0 and 60*60*24*7, do the query, and sort the results however you like.
Alternatively, tell us what you're actually trying to achieve and we might be able to give a better answer.
Related
I'm using MongoDB to store data and when retrieving some, I need a subset which I'm uncertain how to obtain.
The situation is this; items are created in batches, spanning about a month between. When a new batch is added, the previous batch has a deleted_on date set.
Now, depending on when a customer is created, they can always retrieve the current (not deleted) set of items, and all items in the one batch that wasn't deleted when they registered.
Thus, I want to retrieve records that have deleted_on as either null, or all items that have the deleted_on on the closest date in the future from the customer.added_on-date.
In all of my solutions, I run into one of the below problems:
I can get all items that were deleted before the customer was created - but they include all batches - not just the latest one.
I can get the first item that was deleted after the customer was created, but nothing else from the same batch.
I can get all items, but I have to modify the result set afterwards to remove all items that don't apply.
Having to modify the result afterwards is fine, I guess, but undesirable. What's the best way to handle this?
Thanks!
PS. The added_on (on the customer) and deleted_on on the items have indexes.
I'm trying to figure out how to query with filter with Geofire.
Suppose I have restaurants with different category. and I want to add that category to my query. How do I go about this?
One way I have now is querying the key with Geofire, run the for loop through each key and get the restaurant, and insert the appropriate restaurant to the array.
These seems so inefficient. Is there any other way to go about this?
Ideally I will have the filtered results, and only load each item when they're about to be shown.
Cheers!
Firebase queries can only filter by one condition. Geofire already does quite some "magic" to allow it to filter on both longitude and latitude. Adding another property to that equation might be possible, but is well beyond what Geofire handles by default. See GeoFire: How to add extra conditions within the query?
If you only ever want to access one category at a time, you can put the restaurants in a top-level node per category and point Geofire to one category.
/category1
item1
g: "pns0h0mf2u"
l: [-53.435719, 140.808716]
item2
g: "u417k3dwub"
l: [56.83069, 1.94822]
/category2
item3
g: "8m3rz3s480"
l: [30.902225, -166.66809]
/items
item1: ...
item2: ...
item3: ...
In the above example, we have two categories: category1 with 2 items and category2 with just 1 item. For each item, we see the data that Geofire uses: a geohash and the longitude and latitude. We also keep a single list with the other properties of these 3 items.
But more commonly, you simply do the extra filtering in client-side code. If you're worried about the performance of that: measure it, share the code, JSON data and measurements.
This is an old question, but I've seen it in a few places on the web, so I thought I might share one trick I've used.
The Problem
If you have a large collection in your database, maybe containing hundreds of thousands of keys, for example, it might not be feasible to grab them all. If you're trying to filter results based on location in addition to other criteria, you're stuck with something like:
Execute the location query
Loop through each returned geofire key and grab the corresponding data in the database
Check each returned piece of data to see if it matches the other criteria
Unfortunately, that's a lot of network requests, which is quite slow.
More concretely, let's say we want to get all users within e.g. 100 miles of a particular location that are male and between ages 20 and 25. If there are 10,000 users within 100 miles, that means 10,000 network requests to grab the user data and compare their gender and age.
The Workaround:
You can store the data you need for your comparisons in the geofire key itself, separated by a delimiter. Then, you can just split the keys returned by the geofire query to get access to the data. You still have to filter through them, but it's much faster than sending hundreds or thousands of requests.
For instance, you could use the format:
UserID*gender*age, which might look something like facebook:1234567*male*24. The important points are
Separate data points by a delimiter
Use a valid character for the delimiter -- "It can include any unicode characters except for . $ # [ ] / and ASCII control characters 0-31 and 127.)"
Use a character that is not going to be found elsewhere in your database - I used *, but that might not work for you. Do not use any characters from -0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz, since those are fair-game for keys generated by firebase's push()
Choose a consistent order for the data - in this case, UserID first, then gender, then age.
You can store up to 768 bytes of data in firebase keys, which goes a long way.
Hope this helps!
I would need a cron job that filters all the rows that have (travellingPath.endDate>now) and set them (travellingPath.isActive=false). The travelling path has a toCity property. Now I want to update the quantity of the toCity based on the quantity of the travellingPath and another settings collection.
For example:
a travelling path expired
cron job catches it
get the toCity from the travelling path
get the conversionRate from another collection
based on the toCity.quantity, travellingPath.quantity, conversionRate and random I update the toCity.quantity to a new value, and I also might change the toCity.owner
update the travelling path to isActive=false
My idea would be to query each travelling path that has endDate>now but this could end up with 100000 results so it's not great. I might limit it to 250 results to work properly. Then for each travellingPath I get it's toCity and make the calculations and update the toCity and the travellingPath.
But this seems so not efficient..
do you have better ideas? thanks (:
Yes, that's the way to go. MongoDB updates don't support expressions that depend on other fields. So you're stuck with this:
Retrieve documents one by one or in small batches;
Calculate new values for the fields;
Send updates to the database (one by one or in batches);
Get next portion of documents, repeat until done.
All,
Is it possible to save to the top of the CoreData? If so, how?
For example, every time something is added to the data store, I want it to be inserted at the top. This way, when the results are fetched they would come back sorted by most recent first without having to save the NSDate and fetch with a predicate. Here is a crude example:
Most recent
Earlier
Yesterday
Last Week
Thanks,
James
What is the "top"?
Core Data does not assign any particular order to the objects it stores. If you want to impose some order on the objects, add an attribute to the entity that you want to be ordered and then sort on that attribute when you fetch the objects. So, you could add a serialNumber attribute that always increases. Sorting on that serial number would order the objects.
Add a creationDate in the model, and the following code to your custom implementation of the object:
- (void)awakeFromInsert {
[self setPrimitiveCreationDate:[NSDate date]];
}
I'm new to developing for the iPhone and I'm using Core Data for my data management. My managed objects have a property called creationDate and I need to have a list of all distinct dates that are in the database. To reduce the overhead I set
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:#"creationDate"]];
because that's all that's needed.
I know I can set [fetchRequest setReturnsDistinctResults:YES]; to get the distinct dates, but how can I take only the date part of an NSDate in a fetch request?
thanks,
Thomas
P.S. In SQL this would look something like: SELECT DISTINCT DATE(creationDate) FROM events;
By "date part of an NSDate" I assume you mean as distinct from the time? You can't directly express that for the purposes of distinct results if the entry in the store has the time encoded. What you can do is split the creationDate in your model to a two properties, date and time, and the normalize all the dates to a single time (or if you don't care about the time you can just throw out the time). If you actually still need the time it is there, but you can do queries purely against the date.
If your entity has its own subclass you can do that by writing a custom setter that takes the data, extracts the components via NSDateComponents, and reassembles those into a date via NSCalendar.
Yes, it seems like it should be simpler to deal with dates, but it is necessary to take a somewhat roundabout path.