NSPredicate(s) for NSMetadataQuery to match kMDItemAccessedDates (array) containing a target date?

大城市里の小女人 提交于 2019-12-11 18:47:35

问题


UPDATE: I found an answer though there may still be a better way - see the answer added below.


a spotlight importer imports metadata that is an array of dates in which an item was accessed. Looks like this:

kMDItemAccessedDates               = (
    "2012-06-18 07:00:00 +0000",
    "2013-01-10 08:00:00 +0000",
    "2013-01-15 08:00:00 +0000"
)

I'd like to query for any of these files that were accessed on a particular date the user enters but I'm not finding the right syntax to do this. Wondering if it's possible to do...

The first issue is that the user enters a date which represents a day, not a day and time.

Seemed like I need to search for any date that falls on that day, so logically: ADATE >= user_day_start && ADATE <= user_day_end

Now there is an array of dates in the metadata so I really want it to match if ANY of those dates fall within the user_date day.

Be nice if this worked:

NSDate * date = [NSDate dateWithNaturalLanguageString: inWhenString];
NSDate * endDate = [NSDate dateWithTimeInterval: 86400 sinceDate: date];

predicate = [NSPredicate predicateWithFormat: 
              @"kMDItemAccessedDates between {%@, %@}", date, endDate];

but that throws an exception:

Exception detected while handling key input.
2013-01-16 03:12:57.517 Chatty[96974:403] Unknown type of NSComparisonPredicate 
  given to NSMetadataQuery 
  (kMDItemAccessedDates BETWEEN {CAST(379540800.000000, "NSDate"),
  CAST(379627200.000000, "NSDate")}) 

and seems like it might only work for a single date rather than an array. Adding the "ANY" to the format string like so: "ANY kMDItemAccessedDates between {%@, %@}" ... didn't help, still throwing an exception.

Tried this and it's not throwing an exception, but isn't really working either:

NSPredicate *p1 = [NSPredicate predicateWithFormat: @"kMDItemAccessedDates >= %@", date ];
NSPredicate *p2 = [NSPredicate predicateWithFormat: @"kMDItemAccessedDates <= %@", endDate ];
predicate = [NSCompoundPredicate andPredicateWithSubpredicates: [NSArray arrayWithObjects: p1, p2, nil]];

Wondering if anyone has any ideas on how to make this work... or knows that it's impossible (like have to get them all and then do the filter in memory or something; really hope that's not the case - it could be a long list!).


回答1:


So another few hours digging into internet search results and trying things and I sort of have this working.

NSDate * userDate = [NSDate dateWithNaturalLanguageString: inWhenString];
NSDateComponents * userDateComponents = [[NSCalendar currentCalendar] components: NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate: userDate];
NSDate * dayDate = [[NSCalendar currentCalendar] dateFromComponents: userDateComponents];
dNSLog(@"date %@", dayDate );
NSString * formatStr = [NSDateFormatter dateFormatFromTemplate: @"yyyy-MM-dd" options: 0 locale: nil];
NSDateFormatter * formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat: formatStr];

NSString * dayStr = [formatter stringFromDate: dayDate];
dayStr = [dayStr stringByAppendingString: @"*"];
dNSLog(@"dayString: %@", dayStr );
NSPredicate *p1 = [NSPredicate predicateWithFormat: @"%K >= CAST(%f, \"NSDate\")", @"kMDItemAccessedDates", [dayDate timeIntervalSinceReferenceDate] ];
NSPredicate *p2 = [NSPredicate predicateWithFormat: @"%K <= CAST(%f, \"NSDate\")", @"kMDItemAccessedDates", [dayDate timeIntervalSinceReferenceDate] + 86400.0f ];
predicate = [NSCompoundPredicate andPredicateWithSubpredicates: @[p1, p2]];

There may be other issues with this whole approach (based on how the app updates this array of dates) that may require me to do something else entirely, but this seems to answer the original question of how to fetch only items that were accessed on a particular day.

The key was the CAST(%f, \"NSDate\") I believe.

There might still be a better way, but I thought I'd put this up here in case someone else is digging around for any clues.




回答2:


OK, I think this is the approach you want. I tested this on a folder of files looking at the kMDItemContentTypeTree attribute, which is an array of strings like your case. Basically I am going to create a BEGINSWITH search and it will search the values of that array.

A BEGINSWITH search is a LIKE search except the search word has "*" appended to the end of it. My idea is that you take the user-input date and create a searchString in the form "YYYY-MM-DD" using the techniques to get the year/month/day that I showed in my other post. Then you create a string from those values in that format.

Now you can create your predicate and start the query like this from your userDateString. You'll notice I used %K to insert the kMDItemAccessedDates property.

NSString* userDateString = @"2013-01-15";

NSString* queryKeyString = @"kMDItemAccessedDates";
NSString* searchDate = [userDateString stringByAppendingString:@"*"];
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"%K like %@", queryKeyString, searchDate];

// folderQuery is your NSMetadataQuery
[folderQuery setSearchScopes:[NSArray arrayWithObject:folderPath]]; // the folder you want to search
[folderQuery setPredicate:predicate];
[folderQuery startQuery];


来源:https://stackoverflow.com/questions/14357577/nspredicates-for-nsmetadataquery-to-match-kmditemaccesseddates-array-contain

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!