Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

Data Model Questions

Multiple sort terms on DataObjectSet::sort(), and performance


Reply

7 Posts   2143 Views

Avatar
johnmblack

7 May 2011 at 8:20am Community Member, 61 Posts

I would like to apply multiple sort criteria to a DataObjectSet... here is what I have so far:

   public function getAllChildren_FeaturedOrNewestFirst()
   {
      $dos = $this->AllChildren();
      $dos->sort('Created', 'DESC');
      $dos->sort('Date', 'DESC');
      $dos->sort('Featured', 'DESC');
      return $dos;
   }

So a few questions:
- Is this the "most correct" way to do this? Is there maybe an alternative way of calling this method with arrays so that it's only one statement? (if not, there should be) :-)
- Is the processing effort of these 3 statements 3x the effort of one statement? Or is there some kind of precompiling step which takes all these into account and does one sort, for better performance?
- If this *is* the way to do this, then am I doing it in the right sequence -- I assume that the later statement will have the more residual result -- so the above would return a result set that looks like (Featured then Date then Created).

By the way, if it seems odd that I would sort Date *and* Created ... this is because Date is a user field with default=Now, but only granular to the day, and we might be entering multiple items per day.

Thanks for any and all help,

-John

Avatar
johnmblack

7 May 2011 at 8:22am Community Member, 61 Posts

p.s. Featured is Boolean. I'm also assuming that sorting DESC on Boolean will yield True(1) before False(0) or Null values... so therefore Boolean Desc means "true first". Let me know if you think I have that backwards.

Avatar
swaiba

7 May 2011 at 8:32am Forum Moderator, 1796 Posts

I'd place this in the DataObject (i.e. Page)...

   static $default_sort = 'Created DESC, Date DESC, Featured DESC';

Avatar
johnmblack

7 May 2011 at 9:15am Community Member, 61 Posts

Interesting -- but just so I understand, this goes in the class definition of the object that you'll be returning into this set, correct?

In this specific case, however, this is part of a utility function to fetch *any* item in the entire system, regardless of class, that matches certain criteria. And sometimes the same result needs to be in a different order.

case 1 - listing of press releases, newest first

case 2 - listing of upcoming events, next future first

case 3 - listing of "recent, featured activity" across multiple page/item/class types <-- this is where a static, default sort became difficult

But thank you for your help -- I will definitely use your advice for cases 1 and 2.

Cheers!

-John

Avatar
swaiba

7 May 2011 at 9:30am Forum Moderator, 1796 Posts

Ah, well yes - but I'm assuming that your pages with news and stuff are ones that are only really used for that purpose. And yes I use it for DataObjects to control the default way they are ordered (has_one's, modeladmin search results and every DataObject::get ).

To eek out the most performance in almost all cases with SS you need to use the odd DB::query - especially for many_many joins, but as with any software 1) write it nicely 2) confirm that is really is a bottleneck 3) only optimze the the bottlenecks.

Glad to help someone learning SS as always!

Avatar
simon_w

7 May 2011 at 10:15am (Last edited: 7 May 2011 10:16am), Forum Moderator, 474 Posts

- Is this the "most correct" way to do this? Is there maybe an alternative way of calling this method with arrays so that it's only one statement? (if not, there should be)

I don't think there is a notion of most correct wrt doing something in a certain way. While sort() doesn't accept an array, there are ways to "fudge" the behaviour. A function like:

function getSortString() {
return "$this->Featured\x01$this->Date\x01$this->Created";
}


should allow you to call sort() once, and sort on SortString.

- Is the processing effort of these 3 statements 3x the effort of one statement? Or is there some kind of precompiling step which takes all these into account and does one sort, for better performance?

Yes, it sorts the set three separate times. SilverStripe 3.0 may not have this, as it follows more of a lazy model when getting things from the database.

- If this *is* the way to do this, then am I doing it in the right sequence -- I assume that the later statement will have the more residual result

Due to the way the PHP sort methods work, the last one is the only one guaranteed to actually still be in affect. That is, sort() is not stable.

The way I would do this is with my own DataObject::get() call. Something like:

function getAllChildren_FeaturedOrNewestFirst() {
return DataObject::get('SiteTree', '"ParentID" = ' . $this->ID, '"Featured" DESC, "Date" DESC, "Created" DESC');
}

Avatar
johnmblack

7 May 2011 at 11:13am Community Member, 61 Posts

Done. Thank you; that works perfectly. I generally don't like reinventing the basic methods like Children() but in this case it's warranted.