FetchRequest with NSPredicate not finding results? - ios

I am storing data in a table that has the columns "name" and "series". I am using this NSPredicate to query:
var request : NSFetchRequest = NSFetchRequest(entityName: "Entry")
request.returnsObjectsAsFaults = false
request.predicate = NSPredicate(format: "name = %# AND series = %#", name, series)
return request
The 'name' and 'series' variables are passed in as String arguments, which are also the data types on the table.
For some reason, this query returns no data. If I do a fetch request on this table without specifying a predicate I can see that the data is indeed there. I am not sure what I'm doing wrong.
For what it's worth I have tried enclosing the conditionals in parens but that didn't seem to make a difference either. Thanks in advance!
UPDATE: I've tried many different things but so far nothing is working. I'm really stumped.
For what it's worth it seems like I am having the same issue as this person: NSPredicate Returns No Results with Fetch Request, Works with Array Filtering
But, there isn't anything on that entry stating specifically what the solution to the problem was.

You can check if the data is there by
printing the URL of the application documents directory to the console.
going to this directory in Terminal
running sqlite3 <databaseName>
trying select * from z<entityName> where name = '<nameData>'
You will be able to explore the data and check if it contains what you expect. Don't forget to also check the content of your name and series variables in the code.

Oh wow...thank you everyone so much for all your answers. In the end it turned out that when I was populating the id for inserting a new row into the table, I was looking at a different table to calculate the new primary key id.
So I was overwriting existing records, which is why my query kept failing.
Kids, if you copy/paste your code without rigorously checking it, you're gonna have a bad time.

Related

NSPredicate using Core Data objectID not working inconsistently?

Wonder if anyone can see the obvious thing I seem to be missing here. I'm working on an app that uses a variety of Core Data entities. These entities store references to a variety of other source files. I want the availability/visibility of the Core Data objects to mirror the availability of the source files.
So at launch, I iterate through the sources and if available I add the NSManagedObjectID of any associated CD objects to an NSMutableSet, lets call it availableObjectIDs.
My understanding is that the using the predicate
"self IN..."
for Core Data should evaluate based on objects IDs, so in my fetch query I use the NSPredicate
"self IN %#", availableObjectIDs
This doesn't seem to be working properly. When I fetch objects with entity X, it returns objects whose objectID has not been added to availableObjectIDs. I can evaluate the results using
[availableObjectIDs contains:object.objectID]
and some will return false, even though the predicate should be filtering them out!
Stranger still, the identical predicate does appear to work when fetching entity Y. I cannot see any difference in the entity configurations to explain this. I've tried using an NSComparisonPredicate instead, and it seems to be behaving the same way.
Baffled by this seemingly simple issue. Anyone run into something similar?

Why can't I use a relationship in a NSManagedObject subclass computed property? (CoreData, swift)

I'm using CoreData and I have a Book entity and a ReadingSession entity. Each Book has many ReadingSessions.
If I add this computed property to the Book class, it works:
var sessions: [ReadingSession] {
let request = NSFetchRequest(entityName: "ReadingSession")
let predicate = NSPredicate(format: "book = %#", self)
request.predicate = predicate
return try! DataController.sharedInstance.managedObjectContext.executeFetchRequest(request) as! [ReadingSession]
}
But if I add this one, it doesn't:
var sessions: [ReadingSession] {
return readingSession?.allObjects as! [ReadingSession]
}
This last example sometimes returns the correct array and sometimes just returns an empty array.
I tried the same thing with other relationships inside computed properties and the results are the same.
Why is that? Is there a reason why I shouldn't try doing this? Is my first example a valid workaround, or will it cause me problems later on? Should I give up using computed properties for this and just repeat the code when I need it?
Thanks in advance!
Daniel
Answering my own question, as Wain pointed out in the comments I should be able to use relationships inside computed properties, and my problem was actually somewhere else.
If you're interested in the details read the next paragraph, but, long story short, if you're having the same problem you should look into your relationships and make sure they're set properly as To One or To Many. Also check if you're setting all your properties in the right places and only when necessary.
I edited my question to remove lots of unnecessary details and make it more readable, but in the end the problem was that I had a User entity with a selectedBook property which was set when a user selected a row. I had set it up as a To Many relationship, but a user can have only one selectedBook at a time, so it should have been a To One relationship there. Also when I created a book I set user.selectedBook to it, but the selectedBook property should only be set when a user selected a book from a row. So I was setting and trying to access some of my relationships at all the right times. I tried to access a user.selectedBook before a user had even selected a row, for instance, and then it obviously returned nil, which messed up many other computed properties. Now I fixed all that and I'm able to access all my relationships from within computed properties without any issues.

Any (or best) way to get records from CloudKit that aren't on the device?

I have the following predicate:
let predicate = NSPredicate(format: "NOT (recordID in %#)", recordIDs)
-- recordIDs is an array of CKRecordID objects corresponding to the CKRecords on the device
...that produces a runtime error about the predicate. If I change the predicate format string to something else, the query runs fine. I have the "Query" checkbox checked for all the metadata for this record type in CloudKit.
According to CKQuery documentation:
Key names used in predicates correspond to fields in the currently evaluated record. Key names may include the names of the record’s metadata properties such as "creationDate” or any data fields you added to the record.
According to CKRecord documentation, these are the available metadata for querying:
recordID, recordType, creationDate, creatorUserRecordID, modificationDate, lastModifiedUserRecordID, recordChangeTag
You can use the creation date:
NSPredicate(format: "creationDate > %#", dateLastFetched)
After you pull the records down to the device and save them, save the dateLastFetched and use it for subsequent fetches.
Edit: Be sure to enable the creationDate query index on the CloudKit dashboard (it is not enabled by default like many other indexes)
This is an old question, so I'm not sure if it existed at the time, but the correct way to do this now is to use Apple's built-in server change token support.
Making a giant query including all existing record ID's on the device is going to be slow, and picking a date is going to be imprecise.
The right way to do this is to use CKFetchRecordZoneChangesOperation and pass in a CKServerChangeToken using the operation's configurationsByRecordZoneID property.
The first time you call, pass a nil change token. As records are received, CloudKit will call recordZoneChangeTokensUpdatedBlock with the latest change token. Persist the latest token so the next time you need records from the server, you can just pass in your most recent token and get only what's changed since then.
Enable the meta data index by clicking here:

Using NSPredicate for efficient PFQuery

My app is using Parse as a back end. At some point in the app, i have to query objects that should contain at least one of the tags in another array. To make it clear, in the database i have a class Pictures which has a Tags property that saves tags in an array. In my app, i have an array of tags that i need to compare with. Only the objects that has at least one of the tags stored in the Tags property should be fetched. I tried to using the following PFQuery functions whereKey:containedIn: and whereKey:containsAllObjectsInArray: however none of them does what i want. Now i shifted my attention to NSPredicates. I tried the following:
PFQuery *postsQuery = [PFQuery queryWithClassName:#"Pictures" predicate:[NSPredicate predicateWithFormat:#"ANY Tags MATCHES ANY ", _tags]];
When i run the code i receive the following error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "ANY Tags MATCHES ANY "'
How can i perform such a query or the right NSPredicate for my situation?
As an illustration on what the query should be about for further explanation:
let's say one of the objects in the database has the following in the "Tags" column
Tags = ["music", "video", "picture", "chocolate"]
and the tag array that i want to use in predicate is the following:
tagsArray = #["picture", "French"];
what i'm expecting is receiving the previous object because it has the "picture" tag. If another object doesn't contain at least one of the tags in the tagsArray it shouldn't be fetched.
Edite:
I found out that i can't use Aggregate Operations such as ANY, SOME, ALL, or NONE. could i find another solution?
The other solution is to use cloud code and write the query on the server in Javascript.
Then you just access the new API endpoint that you defined and get the results of the query that way.
Okay, i found out that using whereKey:ContainedIn: actually works out in this case. My problem that i was passing by mistake an array of dictionaries. The one i wanted to use is made of strings.
This is an example of how to use NSPredicate
in swift 4
let predicate1 = "\(PFUser.current()!.objectId!)\(userObj.objectId!)"
let predicate2 = "\(userObj.objectId!)\(PFUser.current()!.objectId!)"
let predicate = NSPredicate(format:"\(CHATS_ID) = '\(predicate1)' OR \(CHATS_ID) = '\(predicate2)' ")
let query = PFQuery(className: CLASS_NAME, predicate: predicate)

Modelling short-term objects in Core Data app

I have an app that talks to the server to get some items (Item class) for current user and store it. So far so good.
I want to implement search, that essentially returns me a set of Item objects, but obviously I do not want to persist every search result there ever be. Another use case is that server API has different endpoints like recommendations/ new/ upcoming/ that return the same Item object, but in different context, so I would like to differentiate between them somehow.
My first thought was to use a throw-away managed context, load objects from API in there, do fetch and when user is done just destroy the context. Is it a good idea in general? It saves code, because most of my VCs already talk to core data.
Rather than throwing the whole wonderful infrastructure of Core Data away, you should leverage it to achieve your purpose.
Add a timestamp attribute to your entity and use it to selectively display search results or even purge your store from old items.
Add a category attribute to your entity and filter by category when searching.
Both can be achieved with an NSPredicate that you add to your NSFetchRequest. For example:
fetchRequest.predicate = [NSPredicate predicateWithFormat:
#"timestamp > %#", [[NSDate date] dateByAddingTimeInterval:numberOfSeconds]];
or
fetchRequest.predicate = [NSPredicate predicateWithFormat:
#"category = %#", #"new"];

Resources