tag:support.flying-sphinx.com,2011-01-05:/discussions/questions/404-searchfilter-by-attribute-of-associated-objectsFlying Sphinx: Discussion 2022-05-03T20:46:51Ztag:support.flying-sphinx.com,2011-01-05:Comment/451283102018-04-19T01:49:12Z2018-04-19T01:49:12ZSearch/filter by attribute of associated objects<div><p>Hi Roger</p>
<p>As you've currently described things (if my understanding is correct), I think it's possible to have everything in a single index:</p>
<pre>
<code>ThinkingSphinx::Index.define :person, with: :active_record do
indexes [firstname, lastname], as: :name, sortable: true
indexes organizations.name, as: :organization_name, sortable: true
# for PostgreSQL:
has "bool_or(organizations.special)", :as => :special, :type => :boolean
# or MySQL:
has "MAX(organizations.special)", :as => :special, :type => :boolean
end</code>
</pre>
<p>And then to search on people who belong to at least one special organisation:</p>
<pre>
<code>Person.search "foo", :with => {:special => true}</code>
</pre>
<p>Does this fit what you need?</p></div>Pat Allantag:support.flying-sphinx.com,2011-01-05:Comment/451283102018-04-19T07:13:39Z2018-11-28T10:06:44ZSearch/filter by attribute of associated objects<div><p>Thanks Pat,</p>
<p>If one person is connected to two organizations, one with <code>special=true</code><br>
and one with <code>special=false</code>, and my search string actually only matches<br>
the name of the latter organization, I don't want the search to return this<br>
person.</p>
<p>Won't your example return the person as long as one or more of that persons<br>
organizations have <code>special=true</code> set?</p>
<p>(I did actually try something like your example before I asked the original question, but just couldn't get my expected result. Perhaps I'm just doing<br>
it wrong or there is something with my actual index setup makes it behave<br>
differently. :/)</p></div>rogertag:support.flying-sphinx.com,2011-01-05:Comment/451283102018-04-19T07:16:09Z2018-11-28T10:06:44ZSearch/filter by attribute of associated objects<div><p>To try to be clear – I <em>also</em> need to do searches where it matches any of<br>
the persons organizations. The one I'm trying to figure our above is just<br>
for an additional special case.</p></div>rogertag:support.flying-sphinx.com,2011-01-05:Comment/451283102018-04-19T15:01:20Z2018-04-19T15:01:20ZSearch/filter by attribute of associated objects<div><p>Ah, yes you're right, what I've suggested will still match names from non-special organisations. Needing that behaviour does change things…</p>
<p>I feel there are two options here. The first is, as you initially suggested, have two indices, and your <code>where</code> clause was spot on. Sharing the rest of the index details across definitions is tricky… you <em>could</em> have a helper class that applies fields and attributes?</p>
<pre>
<code>class IndexDefiner < BasicObject
def self.call(source)
new(source).call
end
def initialize(source)
@source = source
end
def call
# Here goes the common index contents
indexes [firstname, lastname], as: :name, sortable: true
indexes organizations.name, as: :organization_name, sortable: true
end
private
def method_missing(name, *arguments, &block)
@source.__send__ name, *arguments, &block
end
end
# and in the index definitions
ThinkingSphinx::Index.define :person, with: :active_record do
IndexDefiner.call self
end
ThinkingSphinx::Index.define :person, name: :person_with_special_org, with: :active_record do
where 'organizations.special = TRUE'
IndexDefiner.call self
end</code>
</pre>
<p>And then use the <code>:indices => ["person_with_special_org_core"]</code> option in your searches.</p>
<p>A different way is to instead define an index on the joining class, which will only have one organisation rather than many:</p>
<pre>
<code>ThinkingSphinx::Index.define :person_organization, :with => :active_record do
indexes [person.firstname, person.lastname], as: :name, sortable: true
indexes organization.name, as: :organization_name, sortable: true
has organization.special, :as => :special
end</code>
</pre>
<p>And then you can search on that model, loading each person through that:</p>
<pre>
<code>PersonOrganization.search "foo", :with => {:special => true}, :sql => {:include => :person}</code>
</pre>
<p>As for which of these to use? I guess it depends on whether you want the duplicate indices (even with the slightly cleaner approach), or a single model to search on - and whether the full situation you're dealing with works in either setup?</p></div>Pat Allan