NSFetchRequest with no duplications by parameter - ios

I have a simply BWWishlistBook entity which has a property BWBook. One BWBook may belong to many BWWishlistBooks and one BWWishlistBook always have only one BWBook.
Now I have a NSFetchRequest for BWWishlistBook:
let fetchReguest = NSFetchRequest(entityName: "BWWishlistBook")
I need to avoid to fetch wishlist books with the same book inside. is it possible? How to setup predicate then? BWBook has an unique id property.
In MySQL this is DISTINCT. What is in CoreData?

-returnsDistinctResults
/* Returns/sets if the fetch request returns only distinct values for the fields specified by propertiesToFetch.
This value is only used for NSDictionaryResultType.
Defaults to NO. */
#available(iOS 3.0, *)
public var returnsDistinctResults: Bool

Make a fetch on BWBook with a predicate of wishlist.count != 0.
Now you will have a list of books (all distinct) and all of them will have at least one wishlist associated with them.
Now you can just display the first wishlist from each book and you will have a list of wish lists with distinct books.

If you know which BWBook for which you want to fetch BWWishlistBook the easiest (and most performant way) is the fetch it by the relationship on the BWBook.
Maybe something along the lines of
wishlist = bwBook.bwWishlistBooks

Related

Sorting a List in Realm Swift

I have a List of objects, which I need to sort by a date property. I'm using that list to display the items in a UITableView
My problem is that, sorting a List in Realm returns a Results<myItem> instead of a List<myItem> object.
What is the proper way to sort a List in Realm without converting it into a Results object?
Workaround can be:
add extra field like timestamp of your date property (in millis), everytime you insert a record. (not required if you are sorting data based on data field)
sort query data = data!.sorted(byKeyPath: "date", ascending: false) for more options
Realm query will return RLMResult only.for unmanaged object

Get all entries related to a specific Entity based on relationship in Swift Core Data

I have a simple two entity Core Data database
Entity 1
- Attribute 1
- Attribute 2
Entity 2
- Attribue 1
The relationship is defined so for every Entity 1, I can have many Entity 2's.
I have selected a single Entity 1 - via a UITableView
I would now like to retrieve all the Entity 2 records. I am trying with NSPredicate but that seems like it is the wrong way.. Here's that code - which cannot invoke initialize for NSPredicate:
lazy var entity2Predicate: NSPredicate = { return NSPredicate(format: "%K = %#", #keyPath(Entity1.relationship), ascending: true)}()
What is the correct way to define the fetch for all the Entity2 records related to Entity1?
If your Entity2's always relate to exactly one Entity1, I think the simplest way to achieve this involves defining a one-to-many relationship between Entity1 and Entity2 in your Core Data model.
Select Entity1. Under Relationships, click the + button to add a relationship. Name it something meaningful. Since you haven't told us the real names of your entities, I'll call the relationship entityTwos in this example.
Set the Type of relationship to "To Many".
If Entity1 is not required to have any Entity2's, set the relationship to Optional.
Set the Delete Rule to "Cascade" so that when Entity1 is deleted, any related Entity2's are also deleted.
Now, select Entity2. Add a Relationship, give it a name (say entityOne) and set its Inverse to the name of the relationship created in Step 1 (entityTwos in this example).
Uncheck the Optional option, and set the Type to "To One". Set the Delete Rule to "Nullify".
You'll also need to add properties for the relationships in your entity classes. In Entity1:
#NSManaged var entityTwos: NSSet
In Entity2:
#NSManaged var entityOne: Entity1
Having done that, you can easily access all the Entity2's related to an Entity1 without any querying, like this:
//here, entity1 is an instance of Entity1
entity1.entityTwos
What's really cool is you can also go the other way:
//here, entity2 is an instance of Entity2
entity2.entityOne

Predicate to fetch objects which parameter is contained in an specific NSSet

I have following entities:
PBOUser, PBOBusiness and PBOLocation.
PBOUser may have a lot of businesses.
PBOBusiness may have a lot of locations.
PBOLocation may belong to only one business.
PBOBusiness may belong to many users.
I need to find these locations which belong to those businesses that my user owns.
let predicate = NSPredicate(format: "business IN %#", myUser.businesses)
let locations = PBOLocation.MR_findAllWithPredicate(predicate) as? [PBOLocation]
But it doesn't work. How to do this in a quick way?
If you ever wanted to do it as a query you would need to use a SUBQUERY predicate
let predicate = NSPredicate(format: "SUBQUERY(business.users, $user, $user == %#).#count > 0", myUser)
business.users is the keyPath to the collection whose elements you want to test
Each item in the collection is evaluated agains the predicate $user == %#
When each item is evaluated against the predicate we use $user to make that the variable name for the single element to use in the predicate
The SUBQUERY will return a collection of results that match so to summarise we use #count > 0 to say if there was at least one match then this fits our criteria
You could probably come up with a predicate that works. But since you already have a reference to PBOUser, you're making things harder than they need to be. Consider that
PBOUser has a relationship to PBOBusiness
PBOBusiness has a relationship toPBOLocation`
With these relationships, a user's businesses are myUser.businesses, as in your code snippet. So take that one step farther and use the fact that locations are a property of the businesses:
let locations = myUser.businesses.valueForKey("location") as NSSet
This makes use of the fact that valueForKey on an array or set will call valueForKey on each member of the collection, and return the results as the same kind of collection. That's why it's an NSSet-- if you want a sorted array, add a call to sortedArrayUsingDescriptors:.

CoreData fetch with NSSortDescriptor by count of to-many relationship

I have 2 CoreData entities (Person, Pet) with the following relationship:
A Person can have multiple Pets. So, there is a To-Many relationship from Person->Pet.
I want to fetch all Persons, sorted by the count of Pets that they have where the person with the most Pets is first, and the person with the fewest Pets is last.
When fetching a list of Persons, I tried using an NSSortDescriptor like the following:
[NSSortDescriptor sortDescriptorWithKey:#"pets.count" ascending:NO]
I thought that the "pets" property on a "person" would allow me to use the count property of NSSet to sort. Alas, CoreData complains with this error:
Fetch exception to-many key not allowed here
Is this a completely wrong approach? How am I supposed to do something like this with a CoreData fetch?
Thanks in advance for your help.
Try using collection operators:
[NSSortDescriptor sortDescriptorWithKey:#"pets.#count" ascending:NO]
This can't be applied directly though (to a fetch request), you need to execute the fetch and then run the sort on the result array (sortedArrayUsingDescriptors:).
If you want to sort while fetching, you would need to add a (non-transient) attribute to the entity which holds the count number.
Change the format of your key to #"pets.#count"
Take a look at this answer https://stackoverflow.com/a/20317087/2567126
Basically you create a persistent property on the NSManagedObject and update the property count any time a child object is added or removed from the relationship.
I also need to do the same thing but in Swift. I just to follow:
Fetch the request from CoreData without 'count' key-value.
I performed sort (high order function) on the fetched result.
allCategory.sort { (category1, category2) -> Bool in
return category1.tasks?.count > category2.tasks?.count
}
This is working for me.

Core Data with to Many relationship - Creating a NSPredicate with ALL in SUBQUERY

My object graph looks like this
SnapShot -->> Pane --> ManagedImage
I'm trying to find a SnapShot that has the exact ManagedImages contained with in a set.
The code I've got now returns an Array of SnapShots that have one or more of the ManagedImages that are in the set. I then search through the Array to find the correct SnapShot but I'm guessing it would be much faster to filter in the Subquery
With an NSPredicate how can I get the unique SnapShot that has ALL of the ManagedImages that are in the set?
Here's my code
mySet = ... // A unique set of (usually 3) managedImages that I'm trying to find a snapShot for
NSFetchRequest *request = ...
request.entity = [NSEntityDescription entityForName:#"SnapShot" inManagedObjectContext:[self managedObjectContext]];
// Want this to work but sends an exception
//request.predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(self.panes, $pane, ALL $pane.managedImage IN %#).#count != 0", mySet];
// Using this
request.predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(self.panes, $pane, $pane.managedImage IN %#).#count != 0", mySet];
A good rule of thumb is that if you already have managed objects in hand, you don't fetch but instead walk the relationships from the managed objects you have to the managed objects you want.
So, your relationship graph probably actually looks like this:
SnapShot <-->> Pane <--> ManagedImage
or maybe:
SnapShot <<-->> Pane <<--> ManagedImage
Since you have a set of ManagedImage objects all you have to do is walk the keypath of pane.snapShot or panes.snapShots to find the SnapShot objects associated with each ManagedImage object. Then you just extract the unique SnapShot objects.
In the first case, the matter is trivial because of the one-to-one relationship path of
ManagedImage-->Pane-->SnapShot
In the second case, you will need to first get all the unique SnapShot objects:
NSSet *shots=[aMangedImageObj valueForKeyPath:#"distinctUnionOfSets.panes.snapShots"];
... for each ManagedImage instances and then merge all the sets with setByAddingObjectsFromSet: or a similar method to produce a single set of unique objects.
Fetches should be used to find the first objects in graph that you need but once you have the objects, you don't fetch but walk the relationships. Otherwise, there is not much point to having relationships in the first place.

Resources