Jump to content
thomas

OR in PW selectors

Recommended Posts

Hello,

Quick question: can i use selectors like

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

?

(I'm on a mobile and need to know ...can't try before Monday ...)

Thanks,

t

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
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

Share this post


Link to post
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

Share this post


Link to post
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

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

This one is fixed in 2.3.2 dev. 

  • Like 2

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
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

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...