views:

98

answers:

2

How would I do the equivalent of this statement in Core Data? Basically I want to get a list of the 10 most occurrences of foo along w/ how many times it occurs.

Basically I'm recording all of my users searches as individual entries in Core Data. I want to be able to select their 10 most searched items and display them in order starting w/ the most popular. So basically I want something like:


  • Baa | 10
  • Sea | 8
  • Box | 6

etc.....


Thanks for any help you can provide. I'm still new to Core Data.

  SELECT foo,
         COUNT(foo) AS occurances 
    FROM bar 
GROUP BY foo 
ORDER BY occurances DESC 
   LIMIT 10;
A: 

Core Data does not support aggregation expressions. I suggest that you change your model. Your entity say "Search" will have two attributes, searchTerm and occurrences. When performing a new search, check if the given searchTerm exists already, if so increment the occurrences if not insert a new entity. When you want to show the top ten, you can sort the objects by occurrences and display the first 10 items.

UPDATE: Based on your need to present top searches for today/month/year instead of "all time" given in the question, as per the documentation you will have to do this in two steps. Assuming your Entity, SearchEvent, has attributes searchTerm and searchDate:

  1. Use NSPredicate to return all SearchEvents after a given date
  2. Iterate over the results to aggregate the number of occurrences of searchTerm. Use NSMutableDictionary for the grouping

This is potentially an expensive operation, so it may make sense for you to keep the results in a cache that you update in the background

falconcreek
I thought of that but the problem is I want to be able to display the most popular within the last week, month, and year. Any ideas on how to accomplish that?
Kyle Decot
Updated answer given new requirements
falconcreek
+1  A: 

First, create a Core Data Entity that has: userSearchTerm and userSearchDate. And create a record everytime a search is done.

Start the code by declaring the fetch request. And use NSPredicate to filter by date:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"UserSearches" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];

NSPredicate *nameFilter = [NSPredicate predicateWithFormat:@"(userSearchDate like[cd] %@) AND (userSearchTerm like[cd] %@)",weekName,termToFind];
[fetchRequest setPredicate:nameFilter];

The [cd] in the like filter specifies it's not case-sensitive. You may also need to change this filter depending on the date and format you want to use

Then, set the fetchResultType as NSDictionaryResultType:

[fetchRequest setResultType:NSDictionaryResultType];

This will return a dictionary which you can use.

To use aggregate functions you need to use NSExpressionDescription

This is an extensive code and I'm not able to test it correctly for you, but you can read it here. On section Fetching Specific Values, it describes how to do the aggregate functions: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdFetching.html

For a reference of all the available aggregate functions for NSExpression go to function expressionForFunction:arguments: where the list is located.

elcool
Thanks for the response. I tried using: NSExpression *countNameExpression = expressionForFunction:arguments: w/ count: then executing the fetch request but this just gives me the total count. Any ideas on what I'm doing wrong?
Kyle Decot
Did you use NSPredicate before to filter the ones for the specific date and for the search term?I'm editing the answer to include an "AND" statement in the Predicate
elcool
That's the problem. I don't have a search term. I just want all of the search terms from that timespan to be listed in the order of how many time's they have occurred.
Kyle Decot