Comparison of NSPredicate and Spotlight Query Strings
Both Spotlight and the
NSPredicate class implement a query string syntax, and though they are similar, they differ in several respects. One query string can be converted into the other string form, as long as the common subset of functionality is used.
Spotlight and NSPredicate
NSMetadataQuery class, which is the Cocoa interface to Spotlight, uses
NSPredicate in its API. Apart from this, there is no relationship between Spotlight and
NSPredicate. The Spotlight query string syntax is similar to, but different from, the
NSPredicate query string syntax. You can convert one query string into the other string form, as long as you use syntax that both APIs understand. Spotlight's query syntax is a subset of that of
NSPredicate. For a complete description of the Spotlight query expression syntax, see File Metadata Query Expression Syntax, and for a complete description of the
NSPredicate string syntax, see Predicate Format String Syntax.
Spotlight requires comparison clauses to take the form
"KEY operator VALUE" and does not accept
"VALUE operator KEY". Moreover, the kinds of attribute Spotlight accepts for
VALUE are more limited than those accepted by
NSPredicate. As a partial consequence of this limitation, you do not always have to quote literal strings in Spotlight queries. You can omit the quotes when
VALUE is a string and no special operators need to be applied to it. You cannot do this with an
NSPredicate query string, as the result would be ambiguous.
The syntax for denoting case- and diacritic-insensitivity for queries in Spotlight is different from the
NSPredicate version. In Spotlight, you append markers to the end of the comparison string (for example,
"myAttribute == 'foo'cd"). In
NSPredicate strings, you use the
like operator and prefix the markers within ""s (for example,
"myAttribute like[cd] 'foo'"). In both cases,
'cd' means case-insensitive and diacritic-insensitive. Spotlight puts the modifiers on the value,
NSPredicate puts the modifiers on the operator.
You cannot use an
MDQuery operator as the
VALUE of an
"KEY operator VALUE" string. For example, you write an “is-substring-of” expression in Spotlight like this:
"myAttribute = '*foo*'"; in
NSPredicate strings you use the
contains operator, like this:
"myAttribute contains 'foo'". Spotlight takes glob-like expressions,
NSPredicate uses a different operator.
If you use “
*” as left-hand-side key in a comparison expression, in Spotlight it means “any key in the item” and can only be used with
==. You could only use this expression in an
NSPredicate object in conjunction with an
Creating a Predicate Format String From a Spotlight Search in Finder
You can create a predicate format string from a search in Finder. Perform a search, save it, then select the folder where you saved it and choose Show Info—the Info panel shows the query that is used by Spotlight. Note however, that there are slight differences between the
NSPredicate format string and the one stored in Finder. The Finder string might look like the following example.
(((* = "FooBar*"wcd) || (kMDItemTextContent = "FooBar*"cd))
&& (kMDItemContentType != com.apple.mail.emlx)
&& (kMDItemContentType != public.vcard))
Typically all you have to do to convert the Spotlight query into a predicate format string is make sure the predicate does not start with
* (this is not supported by
NSMetadataQuery when parsing a predicate). In addition, when you want to use a wildcard, you should use
LIKE, as shown in the following example.
((kMDItemTextContent LIKE[cd] "FooBar")
&& (kMDItemContentType != "com.apple.mail.emlx")
&& (kMDItemContentType != "public.vcard"))