NSFetchedResultsController with different sort descriptors by section? - core-data

I have an NSFetchedResultsController that I has the first sorting descriptor of the sort descriptors array as the same as the sectionNameKeyPath, thus giving me different sections. But I want the second sort descriptor to be different pr section. Is there a good way to do this without me having to push the data into arrays that I then sort again?
Cheers
Nik

You already suggested using different arrays internally for each section. That's not a bad approach, because in reality you only have to worry about a mapping between index paths of the displayed objects and the real objects.
In other words, you know the small number of items the table view is displaying because it asks the controller for those. You don't have to give it back the items directly from the array of fetched results in the FRC.
Take the index path, figure out which section is being requested, and grab your pre-sorted rows for that section. Since the data is pretty small, you may get away with sorting them on the fly as they are requested.
Another method is to just add another attribute to the data model. This attribute represents the sort order within the section, and you can set it to whatever values you want, since the whole array will be sorted first by section, then by that attribute.
Also, you may find it easier to use a proxy object as a front-end to the fetched results controller. Similar to the "multiple arrays" approach, you just use a proxy object that applies unique sort descriptors on each section when that section is requested by the table view, and returns the objects in its own sorted order.

Related

Does ArangoDB "know" what attributes exist in a collection? (shapes data)

There's a recipe how to sample documents and determine their structure:
https://docs.arangodb.com/cookbook/AccessingShapesData.html
It is stated, that you can't query internal shapes data. But examining some documents will only approximate what attribute keys are used, or the entire collection must be scanned.
So my question is: does the database store what attributes exist somewhere internally? At least for common attributes?
If yes, why isn't it possible to query that data? It would be far more efficient than a user-defined function that outputs roughly the same information.
It would be great if one could discover schemes "for free":
http://som-research.uoc.edu/tools/jsonDiscoverer/#/
Whenever an attribute is used first in a collection, ArangoDB will store this somewhere internally. That means it does keep track of which attributes were used in a collection. There are a few issues however:
the attribute names are stored globally, but nested attribute names are stored separately (ex: user.name will be stored as user and name). From looking at purely the separate attribute name parts, ArangoDB will not know in which combinations they are used in the data
attribute names are stored whenever an attribute name is first used in a collection. Currently ArangoDB does not keep track of when an attribute is not used anymore. The attribute name will then still be present in the list of attributes
Under these restrictions, the list of attributes could be made available, but I am not sure how useful this will be.

Best way to build a custom table linked to a NotesView with sorting and paging

I have a view in my Xpage application that contains a lot of elements. From this view I need to build a table with custom rows (I can't just display the view, I need to build the rows to display myself because I need to compute data from other database, things that you can't do directly in a view).
In order to do so I know that I can use Dataview, Datatable or repeat control (other ideas maybe?). For sure I can't bring all the data on the client, it's way too much.
I am looking for a solution that will allow me to do paging (easy to do with the pager component) but more important sorting on header click. To be clear, I need sorting for all the entries of the view and not only for the current displayed page on the client.
What can be the more efficient way to do so ? I really have a lot of data to compute so I need the fastest way to do it.
(I can create several views with different sorting criteria if needed).
Any repeating control can have pagers applied to it. Also View Panels can include data not in the current view - just set the columnName property to blank and compute the value property. bear in mind you will not be able to sort on those column though - they're not columns, they're values computed at display time.
Any computed data is only computed for the entries currently shown. So if you have 5000 entries in the view but are only displaying 30 at a time, the computed data will only be computed for the current 30.
If your users need to be able to sort on all columns and you have a lot of data, basically they have to accept that they're requirements mean all that data needs computing when they enter the view...and whenever it's updated, by themselves or any other users. That's never going to be quick, and the requirements are the issue there, not the architecture. RDBMS may be better as a back-end, if that's a requirement, as long as the data doesn't go across multiple tables. Otherwise graph database structure may be a better alternative.
The bigger question is why the users need to sort on any column. Do the users really want to sort on the fifth column and then scroll down to entries beginning with a "H"? Do they want to sort on the fourth column and scroll down to entries for May 2014? On a Notes Client, that's a traditional approach, because it's easier than filtering. But usually users know what they're looking for - they don't want entries beginning "H", they want entries where the department is HR. If that's the case, sorting on all columns and paging is not the most efficient method either from a database design or a usability point of view.
To keep the processing faster and lightweight, I use JSON with JQuery DataTables.
Depending on the Data-size and usage, JSON could be generated on the fly or scheduled basis and saved in Lotus Notes Documents or ApplicationScope variables.
$.each(data, function(i, item) {
dataTable.row.add( [data[i].something1,data[i].something2,data[i].something3])
});
You can compute a viewColumn but if you have a lot going on I wouldn't go that route.
This is where Java in XPages SHINE!
Build a Java object to represent your row. So in java use backend logic to get all the data you need. Let's say you have a report of Sales Orders for a a company. And sales orders is pulling data from different places. Your company object would have a method like:
List<salesOrder> getOrders() {}
so in the repeat you call company.getOrders() and it returns all the rows that you worked out in java and populated. So your "rowData" collection name in the repeat can access all the data you want. Just build it into a table.
But now the sorting... We've been using jQuery DataTables to do just this.. It's all client side... your repeat comes down and then the DataTables kicks in and can make everything sortable... no need to rely on views.. works great...
Now it's all client side but supports paging and works pretty decent. If you're just pumping out LOTS of records - 6,000+ then you might want to look at outputting the data as json and taking advatange of some server cacheing... We're starting to use it with some really big output.. LOTS of rows and it's working well so far. Hopefully I'll have some examples on NotesIn9.com in the near future.

Supplying UITableView Core Data the old-fashioned way

Does anyone have an example of how to efficiently provide a UITableView with data from a Core Data model, preferable including the use of sections (via a referenced property), without the use of NSFetchedResultsController?
How was this done before NSFetchedResultsController became available? Ideally the sample should only get the data that's being viewed and make extra requests when necessary.
Thanks,
Tim
For the record, I agree with CommaToast that there's at best a very limited set of reasons to implement an alternative version of NSFetchedResultsController. Indeed I'm unable to think of an occasion when I would advocate doing so.
That being said, for the purpose of education, I'd imagine that:
upon creation, NSFetchedResultsController runs the relevant NSFetchRequest against the managed object context to create the initial result set;
subsequently — if it has a delegate — it listens for NSManagedObjectContextObjectsDidChangeNotification from the managed object context. Upon receiving that notification it updates its result set.
Fetch requests sit atop predicates and predicates can't always be broken down into the keys they reference (eg, if you create one via predicateWithBlock:). Furthermore although the inserted and deleted lists are quite explicit, the list of changed objects doesn't provide clues as to how those objects have changed. So I'd imagine it just reruns the predicate supplied in the fetch request against the combined set of changed and inserted records, then suitably accumulates the results, dropping anything from the deleted set that it did previously consider a result.
There are probably more efficient things you could do whenever dealing with a fetch request with a fetch limit. Obvious observations, straight off the top of my head:
if you already had enough objects, none of those were deleted or modified and none of the newly inserted or modified objects have a higher sort position than the objects you had then there's obviously no changes to propagate and you needn't run a new query;
even if you've lost some of the objects you had, if you kept whichever was lowest then you've got an upper bound for everything that didn't change, so if the changed and inserted ones together with those you already had make more then enough then you can also avoid a new query.
The logical extension would seem to be that you need re-interrogate the managed object context only if you come out in a position where the deletions, insertions and changes modify your sorted list so that — before you chop it down to the given fetch limit — the bottom object isn't one you had from last time. The reasoning being that you don't already know anything about the stored objects you don't have hold of versus the insertions and modifications; you only know about how those you don't have hold of compare to those you previously had.

Core Data: am I on the right track? Setting up data model for data that contains multiple arrays, eg. accelerometer data

I am working on a project that involves a lot of data, and at first I was doing it all in plist, and I realized it was getting out of hand and I would have to learn Core Data. I'm still not entirely sure whether I can do what I want in Core Data, but I think it should work out. I've set up a data model, but I'm not sure if it's the right way to do it. Please read on if you think you can help out and let me know if I'm on the right track. Please bear with me, because I am trying to explain it as thoroughly as I can.
I've got the basic object with attributes set up at the root level; say a person with attributes like a name, date of birth, etc. Pretty simple. You set up one entity like this "Person" in your model, and you can save as many of them as you want in your data and retrieve them as an array, right? It could be sorted based on an attribute in the Person, such as the date they were added to the database.
Now where I get a bit more confused is when I want to store several different collections of data with each person. For example a list of courses and associated test marks. In a plist I would have stored an array of dictionaries that stored this, sorted by the date assessed. The way I set this up in my data model was that I added an entity called "Tests" and a "to-many" relationship from Person to Tests, and then when I pull that I get an NSSet that I can order by a timestamp again? Is there a better way to do this?
Similarly the Person may have a set of arrays of numerical data (the kind that you could graph over time,eg. Nike+ stores your running data like distance vs time, and a person would have multiple runs associated with them, hence a set of arrays, each with their own associated date of collection). The way I set this up is a little different, with a "Runs" attribute with just a timestamp attribute, and that is connected from Person via a to-many relationship, with inverse "forPerson". Then the Runs entity is connected to another entity via a to-many relationship that has attributes to store numerical data and the time. This would once again I would use a time/order attribute to sort them.
So the main question I have is whether using an internal attribute like timestamp to sort a set would be the right way to load in a "array" from core data. Searching forums/stack overflow about how to store NSArrays in core data seem overly complicated compared to this, giving me the sense that I'm misunderstanding something.
Thanks for your help. Sorry for all the text, but I'm new to Core Data and I figure setting up the data model properly is essential before starting to code methods for getting/saving data. If necessary, I can set up a sample model to demonstrate this and post a picture of it.
CoreData will give you NSSets by default. These are convertible to arrays by calling allObjects or sortedArrayUsingDescriptors, if you want a sorted array. The "ordered" property on the relationship description gives you an NSOrderedSet in the managed object. Hashed sets provide quicker adds, access and membership checks, with a penalty (relative to ordered sets) for the sort.

Merge multiple NotesViewEntryCollection and sort on date

I have some NotesViewEntryCollection that I want to merge into one collection, and then sort on date. All the collections are gathered from the same view, so there wont be a conversion problem.
Have tried to google this problem, but cant seem to find any good solutions, besides writing a bunch of for-loops.
Thnx in advance!
Assuming that you're using LotusScript and a recent version of Notes (8+). You can use the merge method. The examples provided in the help, here, should help you get started. Be aware of some caveats when using NotesViewEntryCollections as reported by IBM.
The NotesViewEntryCollection gives you a sorted collection, and the merge method will also give you a unique sorted list of documents, unlike a regular NotesDocumentCollection which is just an unsorted bucket.
I found this out recently, that if you create a NotesViewEntry from one view, you can only add entries that exist in that view. So you can't combine entries from two different views.
A possible way round this would be to use a java.util.TreeMap, push the entries into the TreeMap with the date as the key. This may work, but you may need to convert the NotesViewEntry objects to your own non-Notes objects before adding them in. This will definitely be the case if you want to store them in a managed bean of session or application scope. No matter how you store them, if you use a TreeMap it will have a performance hit if you're dealing with a lot of entries.
If you are using Notes 8.0 or greater, there is a Merge method you can call to merge two collections together. Otherwise, you are correct that you'd have to loop through each collection and call AddEntry to add each entry one at a time.
It does not answer your question, but it might be possible to move all the documents to a (temporary) folder. This folder can take care of the sorting and merging.

Resources