4

I have a view that produces say 70 results with certain exposed filters applied (this is a view that uses Apache Solr indexed content) and I want to get the NID of every result, so I can then send it through to another page in a simple array of NID's.

I've found that all the results NIDS are within the $results array produced by views, but this only has the results that are shown on the current page, is there a way to get all the results disregarding the pager, without removing it entirely. Is this impossible to do without generating a new query based on the active filters? this is what I'm trying to avoid because there are quite a few filters.

  • Can you turn on the Devel module and show what the SQL looks like that your View executes? – beth Mar 19 '14 at 17:52
  • 3
    As soon as you turn on a pager there are two queries run: one that counts the total results (just the count, it doesn't fetch ids), and one with an explicit LIMIT clause that fetches the data. So realistically you'll need to run another query unless you change how the pager works – Clive Mar 19 '14 at 17:57
  • Yeah, @Clive is right. I ran into this a few weeks ago. I have a less than optimal solution if you are interested. – mpdonadio Mar 19 '14 at 17:58
1

You will have to run another query. There is no way around it. However you don't have to use Views for the second query. If you only need a list of nids, an EntityFieldQuery is perfect.

$query = new EntityFieldQuery();

$query->entityCondition('entity_type', 'node')
 // Add whatever filters your user has set. For example...
  ->entityCondition('bundle', 'mynodetype') // Filter by type
  ->propertyCondition('status', 1) // filter by published/unpublished status
  ->fieldCondition('field_foo', 'value', 'bar', '=') // filter by the value of a field
// Order however you want, for example...
  ->fieldOrderBy('field_foo', 'fid', 'DESC') // Order by a field value
// Set the range to get the number you want to see.
  ->range(0, 70)

$result = $query->execute();
$nids = array_keys($result['node']);

That will get you just a list of nids, more quickly and performantly than running a whole separate query such as that generated by a View.

  • 1
    Depending on the circumstances, this may not be true. Views can do some weird stuff when it creates the correlation names, and if you need the nids in the same order as the paged results, you need to be really careful with how things get constructed. – mpdonadio Mar 19 '14 at 18:38
  • True. Caution should be exercised with this method. I recommend testing against expected order, if order is important. – beth Mar 19 '14 at 18:56
3

I ran into this problem on a recent project. I decided against a EntityFieldQuery or db_query()/db_select() solution for four reasons.

  1. Views can do some really weird things when it builds a query. For example, in some instances when you add a sort, the sort key will be added to the returned field list. This can alter what gets returned when you enable aggregation, reduce duplicates, etc.

  2. Views tends to use LEFT JOIN instead of INNER JOIN. You can do this with db_query() and db_select(), but not EntityFieldQuery.

  3. SQL can be unpredictable with the undefined ordering between having a LIMIT or not. For example, if you are sorting by titles and have duplicates, I have seen different results orders. This mans you may need to be really explicit with sorts, if order is important (I was implementing prev/next through a result set, so it was).

  4. I really don't like implementing things in code when I know a non-coder may want to adjust the View.

So, I ended up using this:

$all = views_get_view('my_view');

$all->display['default']->display_options['pager'] = array(
  'type' => 'none',
  'options' => array(
    'offset' => 0,
  ),
);

$all->set_display('my_display');

$all->display[$all->current_display]->display_options['pager'] = array(
  'type' => 'none',
  'options' => array(
    'offset' => 0,
  ),
);

$all->pre_execute();
$all->execute();

$nids = array();

foreach ($all->result as $result) {
  $nids[] = (int) $result->nid;
}

This will

  • Manually instantiate the view.
  • Reset the pager on the master to show all results starting from 0.
  • Set the display to whatever I am using.
  • Reset that pager, too.
  • Execute the view
  • Loop through the results for what I need.

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.