Jump to content


Photo

searching multiple fieldtypes

fieldtypes pagearray

  • Please log in to reply
26 replies to this topic

#1 evan

evan

    Jr. Member

  • Members
  • PipPip
  • 42 posts
  • 10

Posted 29 July 2012 - 09:33 PM

Hi all,

I have a website that has Pages with text and Page fieldtypes. Is there an elegant way to search both of them (in this case, the Page titles of the referenced pages) at the same time for a search string?

Doing a search of the Page titles and bodies is easy enough:


$my_textual_results = $pages->find("body|title%=$query, sort=-posted, limit=10");

And of the referenced Pages, too:

$my_referenced_pages = $pages->get('/referenced-pages/')->find("title%=$query");
$my_referenced_results = $pages->find("referenced_pages=$my_referenced_pages, sort=-posted, limit=10");


Now how do I combine these two search queries into one? I tried an 'or' operator between the two different search parameters:

$my_referenced_pages = $pages->get("/referenced-pages/")->find("title%=$query");
$total_results = $pages->find("body|title%=$query | referenced_pages=$my_referenced_pages, sort=-posted, limit=10");

...but that didn't work.

Any ideas? Thanks!

-evan

#2 slkwrm

slkwrm

    Sr. Member

  • Members
  • PipPipPipPip
  • 248 posts
  • 66

Posted 29 July 2012 - 10:25 PM

You can safely leave your request separate, but merge them afterwards:
$total_results->import($my_textual_results);


#3 diogo

diogo

    Hero Member

  • Moderators
  • 2,015 posts
  • 1098

  • LocationPorto, Portugal

Posted 30 July 2012 - 02:22 AM

You are aware that "get" will only give you the first referenced page? In the search wouldn't work an array anyway, but because the variable is in plural, i get the feeling that you want something different.

edit: I was sleeping when I wrote that... you can use a page array on the selector, and you are using a "find" right after the "get" :)
No more reading PW forum on the mobile! Still you don't really need to do it in two steps, because this would be enough:

$my_referenced_pages = $pages->find("title%=$query, parent=/referenced-pages/");

As for your question: I don't know how to combine them with one query, but with slkwrm's solution you wouldn't have the pages sorted exactly as you want.

#4 ryan

ryan

    Hero Member

  • Administrators
  • 5,812 posts
  • 3139

  • LocationAtlanta, GA

Posted 30 July 2012 - 06:45 AM

Just for clarification, the intended search would be for:

(body OR title contains $query) OR (referenced_pages contains $my_referenced_pages)

and not this?

(body OR title contains $query) AND (referenced_pages contains $my_referenced_pages)

In ProcessWire you can't do the first one in 1 find(), at least not yet. Though the second one you can do and is pretty common:

body|title%=$query, referenced_pages=$my_referenced_pages

I'm hoping to make this possible pretty soon (but it isn't yet):

body|title|referenced_pages.title%=$query

#5 diogo

diogo

    Hero Member

  • Moderators
  • 2,015 posts
  • 1098

  • LocationPorto, Portugal

Posted 30 July 2012 - 07:10 AM

Ryan, I think he wants the first, and THAT would be a great addition to pw :)

It would also work with repeaters?

#6 ryan

ryan

    Hero Member

  • Administrators
  • 5,812 posts
  • 3139

  • LocationAtlanta, GA

Posted 30 July 2012 - 09:11 AM

body|title|referenced_pages.title%=$query


Attached is an update to /wire/modules/Fieldtype/FieldtypePage.module that lets you do this, once you replace your existing file with the one below. You should be able to specify just about any native or custom page field after the dot, like above (where we're using 'title'). If anyone can test it out to confirm I'd appreciate it. I'll commit to the source after testing a little more locally too.

Attached File  FieldtypePage.module   15.31K   66 downloads

It would also work with repeaters?


This type of syntax is already used by repeaters. But if you mean something like: "repeater_field.referenced_pages.title%=$query", I don't think the attached update would let you do that, though havent' tried. If it doesn't, it's probably not much of a stretch to support it though.

#7 diogo

diogo

    Hero Member

  • Moderators
  • 2,015 posts
  • 1098

  • LocationPorto, Portugal

Posted 30 July 2012 - 09:35 AM

Actually I meant the normal use for repeaters... disregard that.

I tried the module. it seems to work fine :)

#8 evan

evan

    Jr. Member

  • Members
  • PipPip
  • 42 posts
  • 10

Posted 30 July 2012 - 10:55 AM

Just for clarification, the intended search would be for:

(body OR title contains $query) OR (referenced_pages contains $my_referenced_pages)


Yep, that's what I wanted to do.

Attached is an update to /wire/modules/Fieldtype/FieldtypePage.module that lets you do this, once you replace your existing file with the one below. You should be able to specify just about any native or custom page field after the dot, like above (where we're using 'title'). If anyone can test it out to confirm I'd appreciate it. I'll commit to the source after testing a little more locally too.

Attached File  FieldtypePage.module   15.31K   66 downloads


Wow, totally amazing! Thanks so much Ryan! It works perfectly on my end.

#9 thomas

thomas

    Distinguished Member

  • Members
  • PipPipPipPip
  • 115 posts
  • 33

  • LocationKöln, Germany

Posted 30 July 2012 - 11:07 AM

I just used this for my search question (http://processwire.c...ieldtype-pages/) and it works great. Thanks!

#10 slkwrm

slkwrm

    Sr. Member

  • Members
  • PipPipPipPip
  • 248 posts
  • 66

Posted 30 July 2012 - 11:59 AM

Tried it out too, works great!

Experimenting with selectors I found something that makes me now ask the following question:

$results1 = $pages->find("$selector1");
$results2 = $pages->find("$selector2");  
$allResults = $results1->import($results2)->sort("-modified")->find("limit=5");

This code works. But if I use the following code, it ignores the second parameter (limit):

$allResults = $results1->import($results2)->find("sort=-modified, limit=5");

And if I switch them to find("limit=5, sort=-modified") then sort parameter is ignored. Is it ok?

#11 Soma

Soma

    Hero Member

  • Moderators
  • 3,218 posts
  • 1769

  • LocationSH, Switzerland

Posted 30 July 2012 - 12:13 PM

$allResults = $results1->import($results2)->find("sort=-modified")->limit(5);

@somartist | modules created | support me, flattr my work flattr.com


#12 slkwrm

slkwrm

    Sr. Member

  • Members
  • PipPipPipPip
  • 248 posts
  • 66

Posted 30 July 2012 - 01:00 PM

Soma, your example doesn't work for me. I guess limit() function doesn't exist, am I right? :huh: My question here is: Why is the second selector in my example ignored? I'm sure Ryan can help here :)

#13 Soma

Soma

    Hero Member

  • Moderators
  • 3,218 posts
  • 1769

  • LocationSH, Switzerland

Posted 30 July 2012 - 01:04 PM

Sorry wrong brain.
$allResults = $results1->import($results2)->sort('-modified')->find("limit=5");

Ryan can't help much here. ;)

@somartist | modules created | support me, flattr my work flattr.com


#14 ryan

ryan

    Hero Member

  • Administrators
  • 5,812 posts
  • 3139

  • LocationAtlanta, GA

Posted 31 July 2012 - 11:57 AM

This code works. But if I use the following code, it ignores the second parameter (limit):


This sounds like a bug to me. I'll take a closer look here, thanks for pointing it out.

#15 nik

nik

    Sr. Member

  • Members
  • PipPipPipPip
  • 204 posts
  • 332

  • LocationTampere, Finland

Posted 01 August 2012 - 04:17 PM

body|title|referenced_pages.title%=$query


I've got an almost similar issue as evan did - except for that I'd need this applied to parent page as well (parent.title instead of referenced_pages.title). So, Ryan, do you think there was a way to achieve this?

I've got a page structure of this kind: /countries/<country>[/<state>]/<city>/<data> (yes, the same again =) and would like to list data pages having search terms in their title OR in their parents (city page) title, sorted by the titles of the found data pages. Having thousands of data pages a lightweight pagination support is a must (one implemented at the database level that is) and making two different finds and joining the results afterwards would leave me without such.

I think the proper way around this would be to use either-or selectors (as evan had tried in the first place) but they're only mentioned in the roadmap for PW versions 2.4+.

My current solution is a module with a horrible hack and plenty of copied core code letting me do a find operation using plain SQL (UNION of the two find statements). It sure does work at the moment but as the site evolves, my mostly hardcoded SQL statements will most probably fail sooner or later. So, what I'm working on now is a more generic module implementing one variation of either-or selectors. It seems to be possible to get working, but has even more copied core code.

But now this recent development on Page fields left me thinking there may be some other solution to my problem, an easier one I hope :). And at least it's time to get a second opinion on how to try to solve this. I'm eager to make this into a module (or even core code) if there happens to be a suitable solution available - one that I'm able to implement with a little guidance to the right direction.

So what do you think, Ryan and others as well?
My modules: Selector Test | After Save Actions | References Tab ~ Other: Tests for ProcessWire core (work in progress)

#16 Soma

Soma

    Hero Member

  • Moderators
  • 3,218 posts
  • 1769

  • LocationSH, Switzerland

Posted 01 August 2012 - 06:02 PM

This sounds like a bug to me. I'll take a closer look here, thanks for pointing it out.


But this really works, there's no bug here:

$allResults = $results1->import($results2)->sort('-modified')->find("limit=5");




Do you mean with making it one selector? This has never worked I think, also MadeMyDay has found about it some time ago.

@somartist | modules created | support me, flattr my work flattr.com


#17 WillyC

WillyC

    Sr. Member

  • Members
  • PipPipPipPip
  • 166 posts
  • 212

Posted 01 August 2012 - 06:25 PM

It is
bug

#18 Soma

Soma

    Hero Member

  • Moderators
  • 3,218 posts
  • 1769

  • LocationSH, Switzerland

Posted 01 August 2012 - 06:50 PM

I've got an almost similar issue as evan did - except for that I'd need this applied to parent page as well (parent.title instead of referenced_pages.title). So, Ryan, do you think there was a way to achieve this?

I've got a page structure of this kind: /countries/<country>[/<state>]/<city>/<data> (yes, the same again =) and would like to list data pages having search terms in their title OR in their parents (city page) title, sorted by the titles of the found data pages. Having thousands of data pages a lightweight pagination support is a must (one implemented at the database level that is) and making two different finds and joining the results afterwards would leave me without such.

I think the proper way around this would be to use either-or selectors (as evan had tried in the first place) but they're only mentioned in the roadmap for PW versions 2.4+.

My current solution is a module with a horrible hack and plenty of copied core code letting me do a find operation using plain SQL (UNION of the two find statements). It sure does work at the moment but as the site evolves, my mostly hardcoded SQL statements will most probably fail sooner or later. So, what I'm working on now is a more generic module implementing one variation of either-or selectors. It seems to be possible to get working, but has even more copied core code.

But now this recent development on Page fields left me thinking there may be some other solution to my problem, an easier one I hope :). And at least it's time to get a second opinion on how to try to solve this. I'm eager to make this into a module (or even core code) if there happens to be a suitable solution available - one that I'm able to implement with a little guidance to the right direction.

So what do you think, Ryan and others as well?


I think it would be possible merging 2 results, but it may not as optimized loading the page array ( though not whole page object ) for thousands of pages. But if it's not 100'000 I think it should work. Also it would be possible to create a pagination by hand.

On the other hand building sql queries aren't really save maybe but can be most optimized choice.

Though what you could do which would be as optimized is use a hidden field on template so store parent title. Create a autojoin field "parent_title". Then populate that field using a hook module. Then you can do:

$results = $pages->find("parent_title|title%=searchtext");

So you could write and autoload that stores the parent title on page save or move and parent save to update all children pages. Also a bootstrap script that you can update after changes or a lazy cronjob or cronjob that update's all in one call (all parents children)

@somartist | modules created | support me, flattr my work flattr.com


#19 ryan

ryan

    Hero Member

  • Administrators
  • 5,812 posts
  • 3139

  • LocationAtlanta, GA

Posted 02 August 2012 - 10:44 AM

The subfields on page references update is now committed in the core so that you can do these types of queries (as mentioned above):

referenced_pages.title*=$query

Also want to mention a limitation: You can't do this with in-memory selection (at least not yet). So the find(), filter() and not() in WireArray/PageArray won't recognize this… just the PageFinder ($pages API var). I'm guessing it'll be awhile before someone even tries it, but just wanted to mention it.

I've got an almost similar issue as evan did - except for that I'd need this applied to parent page as well (parent.title instead of referenced_pages.title). So, Ryan, do you think there was a way to achieve this?


I think so. It was a pretty simple matter supporting the subfields of page references, so I think the same would go for parent. I will look into it here more and hopefully get this added soon. Seems like a very nice thing to have.

This code works. But if I use the following code, it ignores the second parameter (limit):

$allResults = $results1->import($results2)->find("sort=-modified, limit=5");
And if I switch them to find("limit=5, sort=-modified") then sort parameter is ignored. Is it ok?


This bug should now be fixed and committed to the core. It sounds like MadeMyDay mentioned this issue too (?), but somehow I missed that message. Thanks to both of you for tracking it down and sorry I missed the message about it the first time around.

#20 Soma

Soma

    Hero Member

  • Moderators
  • 3,218 posts
  • 1769

  • LocationSH, Switzerland

Posted 02 August 2012 - 10:58 AM

Thanks Ryan! Well he mentioned it on IRC, so I remembered to split it up so it works from a forum post.. not sure it really was about the exactly same, but order of selector fields matters. :) Some things he recognized he make a post you even liked. http://processwire.c...s-on-selectors/

@somartist | modules created | support me, flattr my work flattr.com





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users