Skip to content
theodox edited this page Apr 24, 2016 · 5 revisions

The most common activity in a minq query is filtering: winnowing a stream down to a more precisely targeted selection on of objects.

There are a couple of distinct types of filtering.

only() to filter by type

The only() function of a stream filters by Maya node types. For example

 Scene().only(Meshes)

will yield only mesh nodes: it's equivalent to cmds.ls(type=mesh`)

where() to filter by a condition

where accepts a one-argument callable as an argument. It will call that function on every element in the stream, passing only those values which return a True or truthy value for the filter function. For example:

def has_p(name):
    return 'p' in name

print Cameras().get(Parents).where(has_p)
# Stream([u'|persp', u'|top'])

The function can do anything it wants -- the only requirement is that it accepts a single argument. For convenience you can use where_not() to negate a filter function:

print Cameras().get(Parents).where_not(has_p)
# Stream([u'|front', u'|side'])

For the common case of querying maya node attributes, there's a special syntax that allows you to avoid writing a function just to call and test getAttr. The minq keyword item is actually a query factory which creates getAttr tests for you, so you can write

Cameras().where(item.orthographic == True)
# Result: Stream([u'|front|frontShape', u'|side|sideShape', u'|top|topShape']) # 

instead of

def is_ortho(cam):
    return cmds.getAttr(cam + ".orthographic")    
Cameras().where(is_ortho)

Using item is also faster than a getAttr filter function as well: see Atribute Queries for more details.

having() to filter by attribute existence

If you want to narrow to a set of objects which have a certain attribute, the having() filter will pass only objects which have the attribute in question. This doesn't check the value of the attribute, only it's existence. For example

Shapes().having('orthographic')
# Result: Stream([u'|front|frontShape', u'|persp|perspShape', u'|side|sideShape', u'|top|topShape']) # 

having uses cmds.ls(o=True) so it's very fast, even compared to an attribute query created with item.

like() to filter by name

like() is used to filter object names as strings. In its simplest form it simply does a case insensitive partial match: if you pass in a sub-string as an argument, it will match any occurrence:

 Cameras().like('r')
 # Result: Stream([u'|front|frontShape', u'|persp|perspShape']) # 

You can however force like to require an exact match by passing the exact flag. Thus:

 Cameras().like('r', exact=True)
 # Result: Stream([]) # 
 # no match because 'r' by itself is not a regex match
 # but add in the necessary wildcards...
 Cameras().like('.*r.*', exact=True)
 # Result: Stream([u'|front|frontShape', u'|persp|perspShape']) # 

It's important to remember that by default, minq streams contain full path names, so objects deep in a hierarchy will still be found by like if one of their parents are! Sometimes that's a very useful feature -- you can find everything under 'r_shoulder' with a single like() query -- but sometimes it produces false positives. Since like is a regular expression, however, you can limit matches to the end of a path name using the $. In this example a plain check on 'arm' would collect hands and fingers because of the path name, but arm$ only collects items which end with "arm".

Joints().like('arm$')
# Result: Stream([u'LeftArm', u'LeftForeArm', u'RightArm', u'RightForeArm']) # 

You can use any Python regular expression as an argument; for example Joints().like('spine[24]$') will find Spine2 and Spine4 but not Spine1 or Spine3 (for a great python regex tester, check out Pythex.org).