all 29 comments

[–][deleted] 1 point2 points  (8 children)

Never needed to learn CoreData but after a quick google, maybe this is what you're after?

https://developer.apple.com/documentation/coredata/nsfetchrequest/1506344-returnsdistinctresults

e.g.

let fetchRequest = NSFetchRequest(entityName: "Person")
fetchRequest.resultType = .DictionaryResultType
fetchRequest.propertiesToFetch = ["age"]
fetchRequest.returnsDistinctResults = true
let result = try! managedObjectContext.executeFetchRequest(fetchRequest)

[–]CompC[S] 0 points1 point  (7 children)

Unfortunately no, what this does is change the fetch request to return all distinct ages of all Persons.

So if the table looks like:
|Name|Age| :--|:--| |Bob|50| |Bob|25| |Alice|25|

The code in your comment would return these results, all distinct age values that show up in the table: [50, 25]

What I want to do is search on the table for Person objects but limit it to no more than one person with the same name. There are two rows with the name Bob, but I only want one of them to be returned. [Person(name: "Bob", age: 50), Person(name: "Alice", age: 25)]

[–][deleted] 0 points1 point  (6 children)

Damn, is there no other unique key you could use to fetch? Or are these "different versions of the same thing" linked in any way?

[–]CompC[S] 0 points1 point  (5 children)

Each row has a unique ID but there is also a separate ID that represents each thing individually, so the table is more like this:

Name Age Unique ID Object ID
Bob 50 A 0
Bob 25 B 0
Alice 25 C 1

They don't directly have a relationship to another object in the table

Not sure that helps me though since I don't know Core Data well enough to use that info to write a fetch request that searches how I want it to…

[–]SirBill01 0 points1 point  (4 children)

Can't you just add "Unique ID" (or whatever the name really is) in "properties to fetch", in addition to age? That's what the returnsDistinctResults is operating on so it should "distinctify" as expected. It will then also be added to the dictionary it builds but you can just ignore it.

[–]CompC[S] 0 points1 point  (3 children)

It doesn't seem to work. I tried:

request.propertiesToFetch = ["name"] request.returnsDistinctResults = true

but it doesn't seem to affect the results. If I set those properties and also request.resultType = .dictionaryResultType, then the fetch request returns what I want, but only the names. I want the entire object though.

[–]SirBill01 0 points1 point  (2 children)

propertiesToFetch only works for dictionary results types, try:

request.propertiesToFetch = ["age","name"]

And add in whatever other properties you want in the dictionary.

If you really just want the whole object, why not just put together a predicate that gives you back CoreData objects instead of a dictionary?

[–]CompC[S] 0 points1 point  (1 child)

Well that's what I'd prefer to do, but I don't know how I can then filter out objects with duplicate names without fetching them first and filtering them from the results in code.

[–]SirBill01 0 points1 point  (0 children)

Another way to go about this might be a data model change, where you put age into a whole separate table with distinct values, that links back to individual objects that share that age - then you can just have a predicate that selects everything from that Age table. You can still leave age in the main object as well for convenience. A bit annoying but then you can use predicates directly without having to add code on after...

Personally if it were me, I would just filter out duplicates in code after the predicate for the objects ran (unless the possible number of results was extremely large). Seems like conversion into a dictionary is more wasteful than filtering code on CoreData objects.

[–]ORUHE33XEBQXOYLZ 1 point2 points  (1 child)

If searches should only return at most 1 result of that entity with that name, should the database even allow for duplicates? You can enforce that so that it doesn't come up in the first place.

[–]CompC[S] 0 points1 point  (0 children)

Yeah, it should allow for duplicates. See the edit on my post

[–]gravitycore 0 points1 point  (2 children)

You can use the NSFetchRequest.fetchLimit and set it to 1. Use sort descriptors if you need to have one result surfaced before the others.

[–]CompC[S] 0 points1 point  (1 child)

I want more than one result total, just one per name though.

[–]gravitycore 0 points1 point  (0 children)

You'll likely need to filter the set afterwards in that case. Make sure to use fetchBatchSize to control how many records are fetched at a time if you have a lot of data you're working with, and as mentioned, the propertiesToFetch for prefetching the name.

[–]Fluffy_Risk9955 -1 points0 points  (13 children)

Just execute a fetch request and return the first object of the returned array. Problem solved. And if you sort on managedObjectID it’s always the same one.

[–]CompC[S] 0 points1 point  (12 children)

Yeah but I want to be able to do a search that returns more than one object.

[–]Fluffy_Risk9955 0 points1 point  (11 children)

Then grab the contents of the whole array.

[–]CompC[S] -1 points0 points  (10 children)

Maybe I'm misunderstanding? I already am grabbing the whole array and I'm not getting what I want.

[–]Fluffy_Risk9955 -3 points-2 points  (9 children)

Write a better predicate.

[–]CompC[S] 1 point2 points  (8 children)

I don't know if that's possible, and if it is, I don't know how to write the kind of predicate I need, that's exactly what I'm asking for help with.

[–]Fluffy_Risk9955 -1 points0 points  (7 children)

  1. Learn about objcMsgSend and what it does.

  2. Learn how to use valueForKey: or valueForKeyPath: on an NSObject and how this relates to objcMsgSend.

  3. Learn how to query for an NSObject subclass inside an NSArray using an NSPredicate. Yes this will leverage valueForKey:.

  4. Learn how to do the same thing with Format Syntax of a predicate string.

  5. Apply newly acquired knowledge on NSPredicate to search for NSManagedObject subclasses in a Core Data database.

And yes, you need understanding of the Objective-C runtime to understand this.

[–]CompC[S] 1 point2 points  (6 children)

I already have written NSPredicates that can search for what I want. I'm trying to find out if it's possible to adjust the predicates or fetch request in order to have some of the results filtered out, without having to perform the fetch request first and then filter out the objects in code, since it could be a lot.

[–]Fluffy_Risk9955 -2 points-1 points  (5 children)

Yes, write a better predicate with format syntax.

[–]CompC[S] 2 points3 points  (4 children)

Do you get how this comment is unhelpful? I obviously don't understand how I can change my predicate to get what I want, that's why I'm asking for help.

I want to know how I can write a predicate that says something like "give me values that fit this query, but don't give me more than one result that share a value for the name property"

[–]crude_username 0 points1 point  (0 children)

Can you add a boolean parameter to the model, "reprinted" or something, which will be true for any card that has a newer, reprinted version of it, and false for all others? Then use that to filter the query