-2

I have a view with a filter which returns the nodes which contain the word "word" in the field "title". I limited the results to 3 nodes. If there aren't 3 nodes, the rest of the nodes will be the ones which have the word "word" in the field "body".

The results are not fetching automatically first the nodes which contain the word in the field "title" as I would like it to be.
I set up the filters with the operator "or" how could i change it to and if not?

For example

node1
title: word
body: this is...

node2
title: this is the word
body: lsjflsdjf

node3
title: there is
body: this is the word

node 4
title: here is
body: these are the word

So with my view I would like to get back node1, node2 and node3 or 4 and in this order first the ones which have "word" in their title and than the other ones.

0

Views filters automatically work with the AND Operator, so you don't have to do anything special to the Operator configuration if you want to filter titles that contain some word but at the same time that word isn't present in the Body.

Simply add the Title Filter and set it to Contains and enter the "word".

Then add the Body Filter and set it to Does not contain and again enter the "word".

Filters will be executed in the order as you see them listed under Filters.

If you added the Title Filter after the Body Filter so they are in the wrong order, click on the drop-down arrow next to the Add button under Filters and rearrange them so Title comes first. Keep the AND as the Operator.

  • Thank you I reexplained the question because i think it wasnt clear enough – user1619177 Nov 18 '18 at 20:42
  • I'm not sure this is what the OP was asking for. – user26231 Nov 18 '18 at 21:13
  • The new details do change the meaning, at least the way I understood it. I'll add another answer. – prkos Nov 18 '18 at 22:18
  • New details don't change the meaning at all but make it clearer. Using title contains AND body does not contain you will miss node3 and node4. The OP clearly needs an OR and to refine sort options. – user26231 Nov 19 '18 at 12:32
  • Yes, the necessity of OR became clear after the examples were added to the question. I can delete this answer if it's too confusing to keep it now. – prkos Nov 19 '18 at 15:14
0

returns the nodes which contain the word "word" in the field "title" and if not in the field "body".

Filter node title that contain ‘word’. Create an OR and filter by body contain ‘word’.

The results are not fetching automatically first the nodes which contain the word in the field "title"

For this, you need sorts now.

Well, in the past I’ve tagged the view. Implement hook_query_TAG_alter() and add ORDER BY clause to it,

ORDER BY CASE WHEN title LIKE ‘%word%’ THEN 0 ELSE 1 ASC

A Drupal example on that hook. (D7, might need to be adapted).

// Get order by's from the view
$orderBys =& $query->getOrderBy();
// Copy the values
$OriginalOrderBys = $orderBys;

//Double check 'title' is the right column name. 
$query->orderBy('CASE WHEN title LIKE '%word%' THEN 0 ELSE 1 END', 'ASC');

// Move original order by's to the bottom in the same order
// This brings priority to the ones above.
foreach ($OriginalOrderBys as $key => $orderBy){
  $val = $orderBy;
  unset($orderBys[$key]);
  $orderBys[$key] = $val;
}

MySQL example (if someone wants to test directly)

select * from node 
left join node__body on node.nid = node__body.entity_id
left join node__field_title on node.nid = node__field_title.entity_id

where
  node__body.body_value like '%word%' or
  node__field_title.field_title_value like '%word%'

order by  
  case when body_value like '%word%' then 0 else 1 end asc

 

Then add/change the limit to 3.

  • For this, you need sorts now. I reexplained the question but i am not sure how to do this – user1619177 Nov 18 '18 at 20:43
  • @user1619177 I expanded on the sorting bit. – rovr138 Nov 18 '18 at 20:54
  • That is the thing, the OP has no idea how to alter the sort order for the matched nodes. ORDER BY what exactly do you have something in mind ? – user26231 Nov 18 '18 at 21:12
  • @EricLavault not sure if you saw my edit. I added a custom order by example using a CASE. – rovr138 Nov 18 '18 at 21:16
  • @EricLavault It will need tweaking for the fields, but yes, I've used it in the past. I'll try and find that example I've used in the past with that hook. – rovr138 Nov 18 '18 at 21:26
0

This may not be exactly what you're asking in terms of limiting the number of results, but it may give you more ideas about the if not then behavior in Views.

If the limit to have no more than 3 results for a word in Title weren't that important, and you wanted to show the Body word filter only if the Title word results were empty, you could embed View area into No results behaviour:

You create a Views Display with only the Title word filter, and another (Block) Display with only the Body word filter. Save the Views.

Then under the first Display under No results behaviour choose View area from the Global category and choose the second Display, the one that has the Body word filter.

This way your first Display would show results for the Title word filter, and if there were no results for that word, then the Block would be displayed instead showing the Body word filter results.

You can limit how many results are displayed in each case, but there is no easy way to make the views show the Block when the number of results is less than 3, this applies only when there is 0 results.

0

There is no such logical and if not operator.

Your logic requires at least one else statement after the first condition, and you also need a nested condition to yield additional results (from the 'body' field) if the search in 'title' field yielded less than 3 nodes. In a pseudo-code, that logic would be :

if (r = in_title(word)) {
  yield limit(3, r)
  if (r.count < 3) 
    yield limit(3 - r.count, in_body(word)) # additional result
}
else if (in_body(word)) {
  yield limit(3, r)
}

The problem is you can't tell views to do that, views builds and optimizes its db queries, so this kind of logic will end up with an OR because the above is equivalent to this :

# with :
# - condition $a equivalent to in_title(word)
# - condition $b equivalent to in_body(word)

if ($a)
  something
else if ($b)
  something_else

that is equivalent to the following condition :

($a && something OR $b && somethingelse)

Now we have to realize that the something and the somethingelse has to be the same thing, that is for views to yield results based on the query built so far :

($a && something OR $b && something)

equivalent to :

(($a OR $b) && something)

so this ends up with the unwanted OR.

Another thing to realize is that if results are yielded regardless of condition $a and $b (something happens even if no result) is not incompatible with the initial logic, as long as we keep the nested condition, which simplifies a bit :

r = in_title(word)
if (r.count < 3) 
  r += in_body(word))
yield limit(3, r)

Since there is no way to handle such conditional subquery from views admin interface, the nested condition described above cannot be executed in a procedural manner, that means the whole result set has to be gathered and limited prior to condition testing, our pseudo-code ought to be :

r = limit(3, in_title(word) + in_body(word))
yield r

That's it, we have a single db-query-like expression collecting the union (logical OR) of results from the fields title and body : in_title(word) + in_body(word).

All this to say that you must use the OR operator in the views filter options to achieve what you want, nothing more. That means all you need then is to apply proper sort options :

  • you want a set of documents that contains a given word in title OR body (filter options).
  • first those containing the word in title, and then the others (sort options).
  • limiting the entire set to 3 documents (limit options).

What you need to fix is the sort order.

For this you can use some hooks to alter the query once views has done most of the work. For example by implementing hook_views_query_alter or hook_query_TAG_alter you should be able to flag title-matched vs body-matched nodes and alter the sorting order according to these custom node flags.

My point is we are often confused by our own logic before even trying to apply filter/sort options to a data set. The thing is to think first about what -> filtering, without missing any data, then when you have a complete data set, only then you can think about how would these data be sorted.

This is obvious but we sometimes forget that we won't sort anything good if the data set is not complete in the first place.

  • Yes it sounds good but how can i flag title-matched vs body-matched nodes? – user1619177 Nov 18 '18 at 21:28
  • @user1619177 You will need to alter the query via one of the mentioned hooks. I think being more specific would belong to another question on Drupal query altering. Take the time to be familiar with Drupal database API, these hooks offer a lot of possibilities (too many ?). You might also want to try using ORDER BY CASE WHEN statements as suggested by @rovr138, that could do the trick. – user26231 Nov 18 '18 at 21:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.