We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 40045
    • 534 Posts
    I'm trying to optimize my db queries a bit to see if I can gain some performance. One thing I thought would maybe help was to limit the fields that xPDO has to fetch for each query (because I don't need all the fields for certain functionalities). I researched a bit about the select() method for an xPDO-Query and also found the method getSelectColums() which can be used in conjunction with select(). To make this a bit more understandable, here a bit of the code (method getSongs() of a custom class/component):

    public function getSongs(array $fieldquery = array(), $limit = 0, $offset = 0, $sortfield = 'songid', $sortdir = 'ASC') {
    		$query = $this->modx->newQuery('TimelineSong');
    		$query->select($this->modx->getSelectColumns('TimelineSong', 'TimelineSong', '', array('artistwww', 'artistfb', 'artisttw', 'songcovdata', 'songvidsrc', 'songlikes', 'songplays', 'editedon', 'editedby', 'extended', 'deleted', 'published'), true));
    		$query->where($fieldquery);
    		$query->sortby($sortfield, $sortdir);
    		$query->limit($limit, $offset);
    
    		if ( $limit === 1 ) {
    			if ( $song = $this->modx->getObject('TimelineSong', $query) ) {				
    				return $song;
    			} else {
    				return; // return null
    			}
    		} else {
    			if ( $songs = $this->modx->getIterator('TimelineSong', $query) ) {
    				return $songs;
    			} else {
    				return; // return null
    			}		
    		}
    	}
    


    what I try here is to EXCLUDE all the fields listed in the array inside getSelectColumns(), so in my understanding these fields should not be fetched from the db and thus also not be available in the resulting object, right?

    but when I try to check the output with toArray() like

    $songobj = $timeline->getSongs(array(), 1)->toArray('', true);
    


    then I still get ALL the fields from the object, also the ones I try to exclude.

    when I just create an output from the getSelectColums() method I get that:

    `TimelineSong`.`id`, `TimelineSong`.`songid`, `TimelineSong`.`artistname`, `TimelineSong`.`songtitle`, `TimelineSong`.`songsrc`, `TimelineSong`.`songdur`, `TimelineSong`.`songcovsrc`, `TimelineSong`.`songbuysrc`, `TimelineSong`.`songrelease`, `TimelineSong`.`songcharts`, `TimelineSong`.`songvoting`, `TimelineSong`.`songcvotes`, `TimelineSong`.`songvvotes`, `TimelineSong`.`songrank`, `TimelineSong`.`songchange`, `TimelineSong`.`songpub`, `TimelineSong`.`songunpub`, `TimelineSong`.`ignore`
    


    which is actually what I want, just the fields I need, not the others...but why do they show up in the resulting object/array?

    So the question is if I'm not understanding the inner workings right here or if there is something else I miss =)?

    Thanks in advance for any insights!
      • 22303 MODX Staff
      • 10,725 Posts
      This is called lazy loading, and is a feature of xPDO. What happens when you only select some fields for an object is that those fields are marked as lazy. When you call toArray() without telling it to exclude lazy fields, xPDO issues additional queries to retrieve the requested lazy fields. Loading only certain fields into the object is indeed a great way to improve performance and/or reduce memory usage, so long as you do not request the additional field values from that instance.

      The third parameter tells the toArray() method to exclude lazy fields.
      $songobj = $timeline->getSongs(array(), 1)->toArray('', false, true);
        • 40045
        • 534 Posts
        Perfect, that's it =)! Thank you very much for the explanation!
          • 40045
          • 534 Posts
          While implementing the select() method into my xPDO query I experienced some strange stuff when trying to save data back to the object/db, doesn't work...and I found the explanation here: https://forums.modx.com/thread/70112/saving-object-getted-by-getcollection-getiterator (lazy objects cannot be saved as all fields have to be there to save an object)...

          so far so bad =)...but I also found out, that the heavy part of my code doesn't even use my getSongs() method, so the select() optimization didn't have any impact on the performance there because I get the object from a related object with
          $record->getOne('Song')
          and as far as I can see the method getOne() also expects a second parameter $criteria, but what I'm asking myself is if I could somehow limit the fetched fields (like with select()) from there, as I only need specific fields for that task? Maybe with the same procedure as I use getObject()/getIterator(), like:

          $record->getOne('Song', $query);
          


          Would that work?
            • 3749
            • 24,544 Posts
            If a record has more than one song, you want getMany() rather than getOne(). getMany() will take the $criteria argument to select which song or songs are retrieved (it will always return an array).

            With getOne(), the $criteria are for getting the related objects, not the object itself, since getOne() is only for 1:1 relationships. [ed. note: BobRay last edited this post 13 years, 1 month ago.]
              Did I help you? Buy me a beer
              Get my Book: MODX:The Official Guide
              MODX info for everyone: http://bobsguides.com/modx.html
              My MODX Extras
              Bob's Guides is now hosted at A2 MODX Hosting
              • 40045
              • 534 Posts
              Quote from: BobRay at Sep 05, 2013, 06:52 PM
              If a record has more than one song, you want getMany() rather than getOne(). getMany() will take the $criteria argument to select which song or songs are retrieved (it will always return an array).

              With getOne(), the $criteria are for getting the related objects, not the object itself, since getOne() is only for 1:1 relationships.

              Thanks for that explanation Bob! In my case it's the other way around, a $record can only have one Song, but a Song can have many $records.

              In my situation i have a records (which are linked to the corresponding song via field 'songid') and I have to pullin additional information about the song, but I don't want all information/fields of that song, just a subset of the fields...no possibility to do this?
                • 3749
                • 24,544 Posts
                If I'm understanding you, it should be possible by using something like this:

                $selectedRecords = $song->getMany('Records', $criteria);
                  Did I help you? Buy me a beer
                  Get my Book: MODX:The Official Guide
                  MODX info for everyone: http://bobsguides.com/modx.html
                  My MODX Extras
                  Bob's Guides is now hosted at A2 MODX Hosting
                  • 40045
                  • 534 Posts
                  Quote from: BobRay at Sep 07, 2013, 01:37 PM
                  If I'm understanding you, it should be possible by using something like this:

                  $selectedRecords = $song->getMany('Records', $criteria);

                  Actually it's the other way around =), like:

                  $song = $record->getOne('Song', $criteria/$query);


                  so if you said, the $criteria array for getOne() is only for getting related fields, does that mean, I cannot get a subset of the Song object fields with getOne()? What does the $criteria array actually take like input/format? Is it the same as a xPDO query (as shown in the first post)?
                    • 3749
                    • 24,544 Posts
                    I'm not really sure, TBH. I've never used the second argument for anything but was going by the comments in the class file (since there's really nothing about it in the official docs):


                    object $criteria: xPDOCriteria object to get the related objects

                    Since it's referring to "objects" rather than "fields" I'm assuming that it's about getting the getting the related objects of the object you're getting. So if you do $element->getOne('category') you could specify which of the Category's related objects come along for the ride. I could definitely be wrong.

                    OpenGeek could give you a definitive answer.

                      Did I help you? Buy me a beer
                      Get my Book: MODX:The Official Guide
                      MODX info for everyone: http://bobsguides.com/modx.html
                      My MODX Extras
                      Bob's Guides is now hosted at A2 MODX Hosting