NSPredicate for property of object in NSArray of NSArray - ios

I have an objects like the below structure: Transaction has an array of Items. Item has an array of SubItems
#interface Transaction : NSObject
#property (nonatomic, copy) NSString *id;
#property (nonatomic, assign) NSInteger status;
#property (nonatomic, strong) NSArray *items; // array of Item
#end
#interface Item : NSObject
#property (nonatomic, copy) NSString *identifier;
#property (nonatomic, assign) NSInteger price;
#property (nonatomic, strong) NSArray *subitems;
#end
#interface SubItem : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, assign) NSInteger price;
#end
I would like to create predicate to find name and price of Subitem from NSArray of Transaction
pred = [NSPredicate predicateWithFormat:
#"ANY SELF.%K.%K.%K contains %#",
#"items",
#"subitems",
#"name",
#"MY_SUB_ITEM_NAME"];
This generates the error below.
failed: caught "NSInvalidArgumentException", "Can't do regex matching
on object (
MY_SUB_ITEM_NAME )."
However when I use the similar format to find out properties in Transaction. It works fine.
pred = [NSPredicate predicateWithFormat:
#"SELF.%K LIKE %#",
#"identifier",
#"TX001"];
How should I correct my predicate to query property in Item and SubItem

I think that cannot work with -predicateWithFormat: for two aggregation levels. On each level you can have a ANY or an ALL aggregation. So the "right" syntax would be ANY items ANY subitems.… = …. Or ANY items ALL subitems.…= …" or …
You can try to build the predicate manually with NSExpression, probably using subqueries.
Oh, you are not using Core Data, what I assumed. So simply do it manually in a loop or use a computed property.

Related

How to do enumerateObjectsUsingBlock-like stuff with JSONModelArray?

I use JSONModel to hold my app datasource, and use -(id)initWithArray:(NSArray *)array modelClass:(Class)cls generated an JSONModelArray, now I want to do some search stuff like enumerateObjectsUsingBlock: method does. But I found that JSONModelArray is not inherited from NSArray.
So, how can I do this?
Try use BWJSONMatcher to convert json string to a NSArray.
For example, your json string seems like :
[{"name":"Arron","age":20,"grade":2},{"name":"Burrows","age":21,"grade":2}]
All you have to do is declare your own data model:
#interface Student : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, assign) NSInteger age;
#property (nonatomic, assign) NSInteger grade;
#end
BWJSONMatcher will help you convert it to a NSArray in a very neat way:
NSArray *students = [BWJSONMatcher matchJSON:jsonString withClass:[Student class]];

How to filter & fetch records with MagicalRecord?

I've two classes like this,
#class Songs;
#interface Album : NSManagedObject
#property (nonatomic, retain) NSNumber * albumID;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSSet *songs;
#end
#interface Album (CoreDataGeneratedAccessors)
- (void)addSongsObject:(Songs *)value;
- (void)removeSongsObject:(Songs *)value;
- (void)addSongs:(NSSet *)values;
- (void)removeSongs:(NSSet *)values;
#end
#class Album;
#interface Songs : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSNumber * length;
#property (nonatomic, retain) Album *owner;
#end
Suppose, I've 10 albums created and each album have some random (positive) number of songs. Now I want to find & fetch top 5 albums which has the maximum number of songs.
How do I do that with MagicalRecords?
Currently, I'm doing it like this,
NSLog(#"%#",[Album MR_findAllSortedBy:#"albumID" ascending:YES withPredicate:[NSPredicate predicateWithFormat:#"#max.#count.songs"]]);
//NSLog(#"%#",[Album MR_findAllSortedBy:#"albumID" ascending:YES]); //works fine
but its crashes with following message:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format
string "#max.#count.songs"'
Is my predicate string invalid? If yes, what is the correct way to achieve this.
According to this post, you can not sort by count on fetch. You need to fetch all items and than sort and trim them:
NSArray* array = [Album MR_findAll];
array = [array sortedArrayUsingDescriptors:#[ [NSSortDescriptor sortDescriptorWithKey:#"songs.#count" ascending:NO] ] ];
array = [array subarrayWithRange:NSMakeRange(0, MIN( array.count, 5) )];

Find objects which contains subjects with given parameter

I'm trying to figure out NSPredicate which will find all objects which contains subjects with given parameter.
I have this objects:
#interface User : NSManagedObject
#property (nonatomic, strong) NSString * name;
#property (nonatomic, strong) NSMutableOrderedSet * items;
#end
and:
#interface Item : NSManagedObject
#property (nonatomic, strong) NSNumber * itemId;
#end
I have array of users and I want to find all users which contain item with itemId == 1.
Have no more clues how to get it
NSNumber *theItemId = #1; // The id that you are looking for
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY items.itemId == %#", theItemId];
should do it. You can use this predicate in a fetch request to fetch all matching users,
or with filteredArrayUsingPredicate: to filter an array of users.

NSPredicate and custom NSObject

I have a custom NSObject which I need to filter. I have been trying to user NSPredicate to do this, but was unable to so far. Here is my object's structure:
#interface MyBigObject : NSObject
#property (nonatomic, strong) NSString *firstAttribute;
#property (nonatomic, strong) NSString *secondAttribute;
#property (nonatomic, strong) NSMutableArray *featuresArray;
#end
The featuresArray contains other custom objects:
typedef enum {
FeatureExists = YES, //Default
FeatureDoesNotExist = NO,
FeatureNotAvailable
} FeatureValue;
#interface MySmallObject : NSObject
#property (nonatomic, strong) NSString *title;
#property (nonatomic) FeatureValue feature;
#end
I want to only return the objects containing a MySmallObject with a certain title and which has feature == FeatureExists.
I've tried something like (and other variations) but to no success:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(featuresArray, $object, $object.title CONTAINS[c] %# AND $object.feature = %d).#count > 0)", #"Fenced", FeatureExists];
NSLog(#"predicate = %#", predicate);
If I understood correctly, the format of your predicate is wrong. It should be [NSPredicate predicateWithFormat:#"SUBQUERY(featuresArray, $object, $object.title CONTAINS[c] %# AND $object.feature = %d).#count > 0", #"some string", FeatureExists]; where you check in your array if any object matches the requirements.

Get related / associated entities from NSSet - CoreData

I have 2 autogenerated entities :
#interface ContactEntity : Entity
#property (nonatomic, retain) NSString *caption;
#property (nonatomic, retain) NSString *image;
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *text;
#property (nonatomic, retain) NSSet *pointLink;
#end
#interface PointEntity : Entity
#property (nonatomic, retain) NSNumber *latitude;
#property (nonatomic, retain) NSNumber *longitude;
#property (nonatomic, retain) NSSet *entityLink;
#property (nonatomic, retain) EntityEntity *entityTypeLink;
#end
They are linked between each other as ManyToMany, i.e. one contact has many points, one point has many contacts inside.
Then a i get first entity :
ContactModel *contact = [[[ContactModel alloc] init] autorelease];
// this is FetchRequest, returns array of all entities
self.items = [contact list:contact];
// i get only one, all is OK here, this entity has related PointEntity in DB
ContactEntity *contactEntity = [self.items objectAtIndex:self.selection];
And when i try to get related PointEntity using NSSet in selected ContactEntity i always get NULL or empty array. Neither of this works :
NSArray *points = [contactEntity.pointLink allObjects];
PointEntity *pointEntity = [contactEntity.pointLink anyObject];
NSInteger x1 = [points count]; // always 0
id x2 = pointEntity.latitude; // always 0
for (PointEntity *x in contactEntity.pointLink) // isn't enumerated because count = 0
{
id x3 = x.latitude;
}
Any thoughts are appreciated. Did i miss something, maybe i need to use NSPredicate to select entities from PointEntity that are related to ContactEntity?
Thanks.
P.S. My question is similar to this but that suggestion does not work for me, i cannot get loaded associated entities using NSSet of main entity :(
CoreData: many-to-many relationship
Answer is found ... i tried to use property of the autogenerated entities when created new records in CoreData, in the meantime the correct way is to use generated methods like - addPointLinkObject, addEntityLinkObject, etc
Example, i have 3 tables :
Contacts (one person may have many locations)
<< - >>
Points (one location can contain many people)
<< - >
EntityTypes (just a type of a location, in this case type is CONTACT)
One of the entities autogenerated by xCode :
#interface PointEntity : Entity
#property (nonatomic, retain) NSNumber *latitude;
#property (nonatomic, retain) NSNumber *longitude;
#property (nonatomic, retain) NSSet *entityLink; // reference to Contacts table (ManyToMany)
#property (nonatomic, retain) EntityEntity *entityTypeLink; // reference to EntityType table (OneToMany)
#end
#interface PointEntity (CoreDataGeneratedAccessors)
- (void)addEntityLinkObject:(ContactEntity *)value;
- (void)removeEntityLinkObject:(ContactEntity *)value;
- (void)addEntityLink:(NSSet *)values;
- (void)removeEntityLink:(NSSet *)values;
#end
I tried to do the following :
// create 3 new instances - one for each entity
ContactEntity *contactEntity = [model create:model];
PointEntity *pointEntity = [point create:point];
EntityModel *entity = [[[EntityModel alloc] init] autorelease];
entity.name = model.table;
EntityEntity *entityEntity = [[entity list:entity] objectAtIndex:0];
// then i tried to use entity's properties directly to bind entities
// it works, but it works only on DB level when we add new records, but somehow something was missed and thus such selection did not work later - [pointEntity allObjects]
//pointEntity.entityTypeLink = entityEntity; // WRONG !!!
//pointEntity.entityLink = contactEntity.pointLink;
//contactEntity.pointLink = pointEntity.entityLink;
// then i replaced 3 lines above with these ones
[pointEntity addEntityLinkObject:contactEntity]; // CORRECT !!!
[contactEntity addPointLinkObject:pointEntity];
[entityEntity addPointLinkObject:pointEntity];
[context save]; // save changes made with entities in current CoreData context
// now [pointEntity allObjects] and [pointEntity anyObject] work as expected
Useful links -
Coredata and Generated subclass for NSManagedObject with relations
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdAccessorMethods.html#//apple_ref/doc/uid/TP40002154

Resources