Getting distinct list of ID's in CoreData - iphone

What's the most efficient way to perform this query on a CoreData table? To use the standard employees database model -- I want DISTINCT department ID's for all departments that contain employees with job-description "chef." As it happens, there is only a single table (Employees) relevant here -- I don't actually have a departments table, just department ID's that are repeated.

Given the schema you describe, I would execute a fetch with a predicate (format string) like #"jobDescription LIKE 'chef'" and then use key-value coding to get the unique values from the resulting array:
[result valueForKeyPath:#"#distinctUnionOfValues.departmentID"];
or create a set:
NSSet *deparmentIDs = [NSSet setWithArray:[result valueForKey:#"departmentID"]];
Depending on the size of the problem (how many employees), doing the final step in-memory may prove prohibitive. At this point, you'll have to create a Department entity and do the work to make sure you connect appropriate employees to each department. Then you can do a fetch of Departments with a predicate (format string) like #"ANY employees.jobDescription LIKE 'chef'" to get the departments with chef employees.

Related

Selecting columns from different entities

I don't know whether I should be drawing parallels, but unfortunately, that's the only way I can express my issue.
In SQL, suppose we have two tables:
Employee with columns Employee ID, Employee Name, Dept. ID
Deptartment with columns Dept. ID, Dept Name
The Dept ID. in the Employee table is a foreign key with that in the Department table.
Now suppose I want to fetch the following columns:
Employee ID, Employee Name, Department Name
using a SQL such as:
SELECT A.EMPLOYEE_ID, A.EMPLOYEE_NAME, B.DEPT_NAME
FROM EMPLOYEE A, DEPARTMENT B
WHERE A.DEPT_ID = B.DEPT_ID
How would one do this using Core Data in Swift? I guess I'm getting confused by only seeing references to
NSFetchRequest(entityName: entityName)
where the entityName refers to a single entity (table in relational DB lingo)
I'd really appreciate any pointers or examples that can help me clear my doubts.
Thanks
It is certainly possible to create a fetch request that is equivalent to your SQL query. More complex queries can be difficult if not impossible to achieve with a single fetch request. But I recommend trying NOT to draw parallels between CoreData and SQL, at least until you have got to grips with how it works.
To take your example, in the CoreData view of the world, Employee would be an entity with a relationship to another entity, Department. A fetch request based on the Employee entity will return an array of Employee objects, and (assuming you create subclasses of NSManagedObject for each entity) you can access the attributes with simple dot notation:
let employeeName = myEmployeeObject.employeeName
But you can use the same notation to traverse relationships equally easily:
let departmentName = myEmployeeObject.department.departmentName
You don't need to worry about joins, etc; CoreData handles that for you.
Now, suppose you try to do it "the SQL way". You can construct a fetch request based on the Employee entity, but specify "properties to fetch" which likewise traverse the relationship:
let fetch = NSFetchRequest(entity:"Employee")
fetch.propertiesToFetch = ["employeeID", "employeeName", "department.departmentName"]
For this to work, you would need to specify the "resultType" for the fetch request to be DictionaryResultType:
fetch.resultType = .DictionaryResultType
The results from this query would be an array of dictionaries containing the relevant keys and values. But the link with the underlying objects is lost. If you subsequently want to access any details from the relevant Department (or even the Employee), you would have to run a new fetch to get the object itself.

Entity Framework - best practice to get count

I have a Customer table and another Orders table. Each Customer can have many orders (One to many relationship).
I want to get a Customer object and from it get how many orders he has (the actual order data is not relevant at this point). So as I see it I have 2 options:
create a view with another OrdersCount field - and that will be another object in my system.
in my app, when I need the count get the Customer.Orders.Count - but for my understanding that will cause an extra query to run and pull all the orders from the database to that collection.
Is there a correct way to do such thing?
Thanks
You do need a new type, but you don't need to recreate all relevant properties.
from c in context.Customers
// where ...
select new {
Customer = c,
OrderCount = c.Orders.Count()
}
Update code that looks for e.g. the Name property of an item in the result, to look for Customer.Name.

Mongodb Schema considering sub-document to avoid multiple reads

I am trying to come up with a MongoDB document model and would like others opinions. I want to have a Document that represents an Employee. This table will contain all attributes of an employee (I.e. firstName, LastName). Now where I am stuck coming from the relational realm, is the need to store a list of employees an employee can access. In other words lets say Employee A is a Manager. I need to store the direct reports that he manages, in order to use this in various applications. In relational I would have a mapping table that tied an employee to many employees. In mongo not being able join documents, do you think I should utilize an embeded (sub-document) to store the list of accessible employees as part of the Employee document? Any other ideas ?
Unless your using employee groups (Accounting, HR, etc) You'll probably be fine adding the employee name, mongo Object ID, and any other information unique to that manager / employee relationship as a sub document to the managers document.
With that in place you could probably do your reporting on these relationships through a simple aggregation.
This is all IMHO, and begs the question; Is simple aggregation another oxymoron like military intelligence?

CoreData sort on to-many relationship

I'm writing an iOS app which has store of person records, and needs to display lists them sorted in particular ways. There are a variable number of these orderings, and they are generated on the fly, but I would like them to be stored in the datastore. The SQL way to do this is to have a ListPositions table with a list name, an id into the persons table, and a sort key. Then, to display a particular list, I can select all list ListPositions with a given name, pull in the referenced persons, and sort on the sort key. Trying to do this in CoreDatat, however I run into problems. I am trying to do this using a schema like:
Person:
Name
DOB
etc...
positions -->> ListPosition
ListPosition:
listName
sortKey
person --> Person
Then, I can get all the Persons in a given list with the NSPredicate
[NSPredicate predicateWithFormat:#"ANY positions.listName like %#", someList];
This allows me to dynamically add lists against a large set of Persons. The problem is that I am unable to use the sortKey field of ListPosition to sort the Persons. What NSSortDescriptor will do this? And if it is not possible to sort a fetch on the property of one element of a to-many relationship, what is another way to get multiple, dynamic orderings in coredata? I am displaying the lists with a NSFetchedResultsController, so I can't put the lists together myself in memory. I need to do it with a single NSFetchRequest.
You're right-- following a to-many relationship returns an NSSet, which has no inherent sorting. To get sorted results there are a couple of options:
Assuming that Person/ListPosition is a two-way relationship, do a new fetch request for ListPosition entities. Make the predicate match on the "person" relationship from ListPosition, which would look something like [NSPredicate predicateWithFormat:#"person=%#", myPerson]. Use whatever sort descriptor you need on the fetch request.
Follow the relationship as you're doing, which gives you an NSSet. Then use NSSet's -sortedArrayUsingDescriptors: method to convert that to a sorted array.
I think the best approach in this case would be to fetch on ListPosition entity instead. Add the sort Descriptor for sortKey (it would work in this case because the fetch request is on ListPosition entity) and prefetch the Person associated with the the list name using setRelationshipKeyPathsForPrefetching for "person" on the fetch request.
[NSPredicate predicateWithFormat:#"listName like %#", someList];
If I understand your model correctly, each Person has one ListPosition for each list in which it participates. Let's say we have acsending list by their names, so X people have X list positions with the same listName and sortKey.
I would create entity List, that would contain the sortKey attribute and then use it in sort descriptor.
entity List:
- sortKey : string
- ascending : bool
Create sort descriptor and use it in fetch request:
[NSSortDescriptor sortDescriptorWithKey:chosenList.sortKey ascending:chosenList.ascending];
Then you may have as many Lists as you want and you can easily use its sort key to sort all people.
If you want to store the positions in database (you didn't mention attribute index in your ListPosition, or anything similar), you can create “joint entity”:
entity PersonInList:
- index : integer
- person -> Person
- list –> List
Another idea is having ordered set of Person objects directly in List entity.
Get the ListPosition (it will come as a NSMutableSet). Then do a sort on the Set, like this:
NSMutableSet *positionsSet = [personEntity mutableSetValueForKey:#"positions"];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"yourSortKey" ascending:NO];
NSArray *positionsSortedSet = [positionsSet sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
That will give you a sorted out array according to your key.
I usually add an index field (type NSNumber) to an entity. It's very easy to calculate index in adding item. just by
object.index = person.positions.count
so, actually you don't need positions field but positions relationship. connect person entity to ListPosition entity would be enough.

How to setup NSPredicate and NSEntityDescription in Coredata to do complicated SQL query

I know how to create NSPredicate to do sql like "SELECT * FROM DRINK". But how about this query:
"SELECT I.name, D_I.amount
FROM DRINK_INGREDIENT D_I, DRINK, INGREDIENT I
WHERE D_I.drinkID=1 AND DRINK.drinkID=1 AND I.ingredientID = D_I.ingredientID;"
How do I even set the NSEntityDescription, and NSPredicate for this kind of query?
Typically with Core Data you will design and use a data model that meets your needs. You should not think about it in terms of SQL--it does not even have to use SQL for storage--nor should you try to directly translate a SQL query into a fetch request with a predicate, etc.
That said, it can sometimes be helpful to think in terms of SQL WHERE clauses when building predicates, but really fetch requests comes down to what entity you need to get and how the collection should be filtered and/or sorted, etc.
Fetch requests are limited to a single entity, so I think you would need multiple fetch requests to simulate your query.
What does your Core Data data model look like? What are you trying to accomplish? What have you tried so far?
UPDATE
It sounds like your data model includes two entities: Drink and Ingredient with a many-to-many relationship between them:
Drink <<-->> Ingredient
Note that in Core Data, there is no DrinkIngredient entity unless you explicitly create it (there is an additional table for the many-to-many relationship, but it's abstracted away from you). Since you want an amount value associated with the rows in the additional table, I would recommend adding a DrinkIngredient entity in Core Data:
Drink <-->> DrinkIngredient <<--> Ingredient
Note: a DrinkIngredient has exactly one Drink and one Ingredient. Drinks can have many DrinkIngredients and Ingredients can be used by many DrinkIngredients.
It sounds like you want to get the name and amount for the list of ingredients for a particular drink. To do this, simply fetch DrinkIngredient objects with a filter predicate like this:
// assuming "aDrink" is a reference to a particular Drink object
// and "drink" is the relationship from DrinkIngredient to Drink
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"drink == %#",aDrink];
// if the fetch request result array is named "ingredientList"
// and the relationship from DrinkIngredient to Ingredient is "ingredient"
for (DrinkIngredient *di in ingredientList) {
NSString *ingredientName = di.ingredient.name;
NSUInteger amount = di.amount.integerValue;
// use "ingredientName" and "amount" here
}
Since you are using Core Data and not SQL, you do things differently. For example, if you wanted to display an ingredient list with name and amount for all drinks, you would simply fetch all Drink objects (no filter predicate) and you access the ingredients through the relationship from Drink to DrinkIngredient.
Again, you should think about what you are trying to accomplish and design and use your data model appropriately. You should not think about SQL or queries.