NSPredicate for a ANY match based on two properties at once

  • I'm having a hard time figuring out how to construct a query. The
    objects involved are:

    Entry
    - has many tags

    Tag
    - name (string)
    - value (string)

    I want to construct searches such as:

    - find all entries that have a the tag named "priority" with the
    value "1".

    I can use [NSPredicate predicateWithFormat:@"ANY tags.name = %@",
    tag.name] to find all entries that have a particular tag... but I
    don't know how to also figure in the value.

    I don't need this predicate to work with a database, these queries are
    all just being run in memory, with my own custom model objects (not
    using Core Data). If there is no way to do this in a format string, is
    there some way to do it by directly constructing a predicate object?

    Thanks,
    Jesse
  • On Fri, Jun 20, 2008 at 10:56 AM, Jesse Grosjean
    <jesse...> wrote:
    > I'm having a hard time figuring out how to construct a query. The objects
    > involved are:
    >
    > Entry
    > - has many tags
    >
    > Tag
    > - name (string)
    > - value (string)
    >
    > I want to construct searches such as:
    >
    > - find all entries that have a the tag named "priority" with the
    > value "1".
    >
    > I can use [NSPredicate predicateWithFormat:@"ANY tags.name = %@", tag.name]
    > to find all entries that have a particular tag... but I don't know how to
    > also figure in the value.
    >
    > I don't need this predicate to work with a database, these queries are all
    > just being run in memory, with my own custom model objects (not using Core
    > Data). If there is no way to do this in a format string, is there some way
    > to do it by directly constructing a predicate object?
    >
    > Thanks,
    > Jesse
    > _______________________________________________
    >

    Jesse,

    I'm thinking NSCompoundPredicate is what you're looking for.  You
    should be able to do something like this:

    NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:@"ANY
    tags.name = %@", tag.name];
    NSPredicate *valuePredicate = [NSPredicate predicateWithFormat:@"ANY
    tags.value = %@", tag.value];

    NSPredicate *combinedPredicate = [NSComparisonPredicate
    andPredicateWithSubpredicates:[NSArray arrayWithObjects:tagPredicate,
    valuePredicate,nil]];

    If the "simple" predicateWithFormat: predicates don't work,
    NSComparisonPredicates will definitely do what you need (I've never
    tried creating a compound predicate with predicateWithFormat:
    predicates)

    --
    Jim
    http://nukethemfromorbit.com
  • >> I want to construct searches such as:
    >>
    >> - find all entries that have a the tag named "priority" with
    >> the
    >> value "1".

    > NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:@"ANY
    > tags.name = %@", tag.name];
    > NSPredicate *valuePredicate = [NSPredicate predicateWithFormat:@"ANY
    > tags.value = %@", tag.value];
    >
    > NSPredicate *combinedPredicate = [NSComparisonPredicate
    > andPredicateWithSubpredicates:[NSArray arrayWithObjects:tagPredicate,
    > valuePredicate,nil]];

    Thanks, but I don't think this quite works. The problem is that the
    two ANY predicates aren't forced to match against the same tag. So if
    the potential matching entry has multiple tags this query will match
    if any of those tags match the tag name, and if any of the tags values
    match the tag name, but there's no constraint that a the same tag
    value pair matches both constraints.

    Jesse
  • On Fri, Jun 20, 2008 at 2:06 PM, Jesse Grosjean
    <jesse...> wrote:
    >>> I want to construct searches such as:
    >>>
    >>> - find all entries that have a the tag named "priority" with the
    >>> value "1".
    >
    >> NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:@"ANY
    >> tags.name = %@", tag.name];
    >> NSPredicate *valuePredicate = [NSPredicate predicateWithFormat:@"ANY
    >> tags.value = %@", tag.value];
    >>
    >> NSPredicate *combinedPredicate = [NSComparisonPredicate
    >> andPredicateWithSubpredicates:[NSArray arrayWithObjects:tagPredicate,
    >> valuePredicate,nil]];
    >
    > Thanks, but I don't think this quite works. The problem is that the two ANY
    > predicates aren't forced to match against the same tag. So if the potential
    > matching entry has multiple tags this query will match if any of those tags
    > match the tag name, and if any of the tags values match the tag name, but
    > there's no constraint that a the same tag value pair matches both
    > constraints.
    >
    > Jesse
    >

    You are correct, it doesn't work.  And in trying to figure this out,
    I've come to realize that I've used predicates "the hard way" in some
    of my code.  Try this instead:

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"(SUBQUERY(
    tags, $x, $x.name = %@ AND $x.value = %@)<....> != 0)",
    @"aNameToMatch", @"aValueToMatch"];

    Appears that this was a problem in 10.4 and fixed in 10.5.
    NSExpression's documentation for
    expressionForSubquery:usingIteratorVariable:predicate: has some
    discussion about it.

    --
    Jim
    http://nukethemfromorbit.com
  • > You are correct, it doesn't work.  And in trying to figure this out,
    > I've come to realize that I've used predicates "the hard way" in some
    > of my code.  Try this instead:
    >
    > NSPredicate *pred = [NSPredicate predicateWithFormat:@"(SUBQUERY(
    > tags, $x, $x.name = %@ AND $x.value = %@)<....> != 0)",
    > @"aNameToMatch", @"aValueToMatch"];

    Wow, that's it! Somehow I missed the whole SUBQUERY possibility. Thank
    you very much!

    Jesse
previous month june 2008 next month
MTWTFSS
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30            
Go to today