Jump to content

OR in PW selectors


thomas
 Share

Recommended Posts

i think so, from the docs:

 
Specifying multiple selectors

A selector string can match
more than one field. You may specify multiple selectors together by
separating each with a comma. For example, the following selector would
match all pages with a year of 2010 and the word "Hanna" appearing
somewhere in the body:

  • year=2010, body*=Hanna

You may specify as many selectors as you want as long as each is separated by a comma.

OR selectors: matching one value or another

In
instances where you need to match values in a single field with an
either-or expression, the values should be split with the "or" operator,
which is the pipe character "|". The following examples demonstrates
its usage:

  • firstname=Mike|Steve
  • id=123|124|125
  • title*=Red|Blue|Green

Each of the above selectors matches pages that have either of the values specified between the pipe "|".

OR selectors, matching one field or another

This
was already described in the selector fields section above, but is
repeated here for reference. Field names may be separated by a pipe "|"
to indicate an OR condition:

  • body|sidebar*=carbonated

The above selector matches pages that have the word "carbonated" in either the body or sidebar fields.

Link to comment
Share on other sites

Hello,

Quick question: can i use selectors like

$pages->find('fieldA=xy || (fieldA=z && fieldB = x)')

No, unfortunately you can't. That's the "either-or selector" mentioned in roadmap for ProcessWire 2.5+ (Winter 2013/2014).

Those examples from the documentation SiNNuT refers to do mention the or-operator, but it can't be used quite like this. "Or" is fine within a single selector but currently there's no support for having an "or" between two or more selectors, it's always "and" which is denoted by a "," (comma).

On the other hand, if you don't need native pagination for the results of this kind of query (and there won't be too many results!), you could use something along these lines:

$results = $pages->find('fieldA=xy');
$additionalResults = $pages->find('fieldA=z, fieldB=x');
 
// this leaves no duplicates to the PageArray
$results->import($additionalResults);

The resulting PageArray can be also sorted and sliced to get exactly what you need. But again, by now you've already fetched all the matching pages from the database into memory, so this is merely to tidy things up - or the core of a custom pagination of course.

// sort first by fieldA ascending, then by fieldB descending and leave only 10 items starting from index 50
$slicedResults = $results->sort('fieldA, -fieldB')->slice(50, 10);

So for small amount of data there's quite an easy way to get around it. But for larger amount of data you'd need to come up with another kind of method, probably one that depends on the nature of the data you're dealing with.

  • Like 4
Link to comment
Share on other sites

Thanks nik, that's what I thought. I have a rather large list of articles which can be sorted and configured by the user. It also contains 'private' articles and 'drafts' which are only visible to it's creater. Right now I iterate over the complete list but that's becoming too slow. I wonder if this is a good approach:

$noShow = $pages->find('private=1,author!='.$user);

$results = $pages->find('template = video,id!='.$noShow);

there are about 1K articles and counting ...

I'm thankful for all hints!

t

Link to comment
Share on other sites

Looks like that approach should work, at least when there aren't hundreds of private or draft articles. And that allows you to use sort and limit too in the last find().

Actually any other approach would work better in the long run than iterating over the complete list, I guess :).

  • Like 1
Link to comment
Share on other sites

Thanks Nik,

obviously there will be a lot more to exclude than to include but I can't fugure out a way to rephrase those queries for include other than what you posted earlier (using import()). I'll compare those two and ditch the iteration :)

Thanks,

thomas

Link to comment
Share on other sites

  • 3 months later...

Hi folks,

Running into a problem with OR selectors so I thought to use this thread.

Not sure if it's a bug... ;)

Problem is the following selector, which does not work:

template=product, price|weight='', ...

I want products which have no price OR weight entered. However, as soon as one of them has a value, there are no pages returned.

If both are empty, it works...

Problem is that the resulting query from Pw uses AND instead of OR (marked red):

WHERE (pages.templates_id=47)
AND (field_weight.pages_id IS NULL OR field_weight.data='')
AND (field_price.pages_id IS NULL OR field_price.data='')

When testing the selector with a value, it works:

template=product, price|weight='test', ...

translates to

WHERE (pages.templates_id=47)

AND (((field_weight.data='test' ) )
OR ((field_price.data='test' ) ) )

No idea if this is easy to fix or a more complicated one...

Edit:

Submitted an issue on GitHub: https://github.com/ryancramerdesign/ProcessWire/issues/205

Link to comment
Share on other sites

  • 1 year later...
On the other hand, if you don't need native pagination for the results of this kind of query (and there won't be too many results!), you could use something along these lines:
$results = $pages->find('fieldA=xy');
$additionalResults = $pages->find('fieldA=z, fieldB=x');
 
// this leaves no duplicates to the PageArray
$results->import($additionalResults);

Dear Nik,

I'm using PW 2.3.0, and am having the dickens of a time to get something like this to work in a page select field

using the "Custom PHP code to find selectable pages" snippet field, for a select list field called:

domain_ip_select

The field is in a template/fieldset called 'accounts', and references a second template/fieldset called "domain_ips" as the list source.

This works fine and returns all records with the same server_id as the parent account data record.

$p = $pages->get($_GET['id']); 
return $pages->find("parent=/domain_ips/, server_id=$page->server_id_select, include=hidden, sort=domain_ip");

but, I'm trying to get two sets of results for the query, based on whether or not the selectable domain_ip pages have an account_id field that is:

- blank, or

- matches the account_id field already in the edited record.

(i.e. I don't want to see a domain_ip that is already taken by a different account, but I DO want to see the current domain_ip for the current account.)

I tried this, but it didn't work:

$p = $pages->get($_GET['id']);

$pages->find("parent=/domain_ips/,server_id=$page->server_id_select, include=hidden, account_id=$page->account_id");

$pages2->find("parent=/domain_ips/,server_id=$page->server_id_select, include=hidden, account_id=");

$pages->import($pages2);

return $pages;

I'm assuming that my syntax is incorrect in the second example, but I've hit a wall with my knowlege gap.

Thanks for any help!

Peter

Link to comment
Share on other sites

Hi Peter,

I'm not sure if the selector engine has something to take care of this in a more straightforward way now but let's see if I'm able to help you with this approach anyway.

Looks like you're not saving the results of your find() calls into variables. Check my example you're referring to: I'm using $results and $additionalResults to hold the found pages and import the contents of $additionalResults to $results. And remember $pages is a system variable you shouldn't be saving anything to yourself. On top of that, it would be better to find unattached domain_ip's first and import only one page (which you don't have to find by the way), not the other way around.

Something like this would probably work:

// find free ip's
$selectable_domain_ips = $pages->find("parent=/domain_ips/,server_id=$page->server_id_select, include=hidden, account_id=");
// add currently selected one to the list
$selectable_domain_ips->import($page->domain_ip_select);

return $selectable_domain_ips;
It seems you've got a two way relation here - or do you really? For this to work you'd have to take care of (un)setting account_id of domain_ip pages yourself. If you've got that set up and working already you should be fine. If not, I'm sure someone here will help you get there (or suggest a whole another approach to make it simpler). I'm a bit rusty myself not having done anything with PW or PHP in months.

Hope this helps. :)

  • Like 5
Link to comment
Share on other sites

Something like this would probably work:

// find free ip's
$selectable_domain_ips = $pages->find("parent=/domain_ips/,server_id=$page->server_id_select, include=hidden, account_id=");
// add currently selected one to the list
$selectable_domain_ips->import($page->domain_ip_select);

return $selectable_domain_ips;
It seems you've got a two way relation here - or do you really? For this to work you'd have to take care of (un)setting account_id of domain_ip pages yourself. If you've got that set up and working already you should be fine. If not, I'm sure someone here will help you get there (or suggest a whole another approach to make it simpler). I'm a bit rusty myself not having done anything with PW or PHP in months.

Hope this helps. :)

Dear Nik,

That did the trick! Thanks!

I think my stumbling block is that I've come from the Perl / PHP procedural method of coding, and I've not taken adequate time to truly digest the PHP OOP model. So, I run into knowledge gaps with things like objects, etc. Learning  OOP PHP is on my todo list.

I'm not using the admin interface to run this app -- at least not the part above. So, I'll be including code to update the account_id field in the domain_ip data record, after someone selects and saves a selected IP.

By the way, I saw a note from Soma about PW v2.3 being buggy and needing this code in the above custom PHP field:

$p = $pages->get($_GET['id']);

But... with your code above, I don't seem to need that.

Do have any thoughts on that?

Thanks again!!

Peter

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...