Laravel 8 withSum relation default value 0 - eloquent

Will laravel 8's withSum function supports default value?
use App\Models\Post;
$posts = Post::withSum('comments', 'votes')->get();
In this relation laravel returns 'comments_sum_votes' as null if a 'post' has no 'comments'.Can we set it to return 0?

I just bumped into this.
While an eloquent accessor may work in certain situations, doing ORDER BY or GROUP BY on this column still wouldn't return correct results (because the database query would still return null when no records are found).
Alternatively, you could do COALESCE yourself like so, which is more efficient:
$post = Post::query()
->withSum([
'comments' => fn ($query) => $query->select(DB::raw('COALESCE(SUM(votes), 0)')),
], 'votes')
->get();
Ref

Related

Ordering query using lambda expression and Include method

I am working on a Entity-Framework-Core 2.0 query. The query needs to sort 2 tables by the "order" field. So far that's what I have:
return await _context.FieldsetGroup
.Include(e => e.Fieldsets.OrderBy(o => o.Order))
.ThenInclude(e => e.FieldsetFields.OrderBy(o => o.Field.Order))
.ThenInclude(e => e.Field)
.FirstOrDefaultAsync(fsg => fsg.FieldsetGroupId == fieldSetGroupId);
This query returns an exception:
"The property expression 'e => {from Fieldset o in e.Fieldsets orderby [o].Order asc select [o]}' is not valid. The expression should represent a property access: 't => t.MyProperty'. For more information on including related data, see http://go.microsoft.com/fwlink/?LinkID=746393."
How can I sort the 2 tables?
One of the slower parts of database queries is the transport of your selected data from the DBMS to your local process. Hence it is wise to limit the amount of transferred data.
Apparently your FieldSetGroup has zero or more FieldSets. Each FieldSet belongs to exactly one FieldsetGroup. This is identified by the foreign key FieldSetGroupId. The value of this field equals the Id of the FieldSetGroup.
So if you have FieldSetGroupwith Id = 10, and this FieldSetGroup has, 1000 FieldSets, then every FieldSet will have a value of foreign key FieldSetGroupId of 10. No need to transfer this value 1000 times.
Advice: To limit the amount of transferred data, avoid transferring more data than needed, use Select instead of Include and select only the data you actually plan to
use. Use Include if you plan to update the fetched data.
If you use Select, you can order whatever you want:
var result = dbContext.FieldsetGroup
.Where((fieldSetGroup => fieldSetGroup.FieldsetGroupId == fieldSetGroupId)
.Select(fieldSetGroup => new
{
... // select the fieldSetGroup properties you plan to use
FieldSets = fieldSetGroup.FieldSets
.OrderBy(fieldSet => fieldSet.Order)
.Select(fieldSet => new
{
... // only select the fieldSet properties you plan to use
FieldSetFields = fieldSet.FieldSetFields
.OrderBy(fieldSetField => fieldSetField.Order)
.Select(fieldSetField => new
{
...
})
.ToList(),
})
.ToList(),
})
.ToList(),
})
.FirstOrDefault();
You cannot do sorting (OrderBy) inside the Include method. Sort the data after the query.

Laravel insert empty value Postgress error

When creating elements in Laravel 4 using the ORM like so:
FigureModel::create( array( 'numericFieldOne'=>1, 'numericFieldTwo'=> null ) );
FigureModel::create( array( 'numericFieldOne'=>1, 'numericFieldTwo'=> '' ) );
In mysql all is well and all the items are perfect inserterd, no problem so far:
But in postgress, it tries to insert empty values without a quote making postress crash. Like so:
What to do?? Does anyone have an idea about how to tackle this problem? Thanks!!
( and custom setters for each element validating it to be a number or null is not an option )
#pozs Thanks! since you pointed out that the correct error should be a 42601 im once again confidant that the prostgress adapter for this orm is sound.
The solution:
In my case i just have to create setter functions for all the numeric null values in the database something like this
public function setNumericFieldAttribute($var){
$this->attributes['numericField'] = empty($var) ? null : $var;
}
This way the value is always null or a value
Thanks!!
It seems Laravel's debug screen cheats you: if the query really was that, the postgres error would be syntax error at or near "," with SQL state 42601
The problem is, postgres does not accept '' (the empty string) as a valid representation for an integer.
Use one of 0, '0', like:
FigureModel::create(array('worldwideoffices' => 1, 'worldwideemployees' => 0));
FigureModel::create(array('worldwideoffices' => 1, 'worldwideemployees' => '0'));
But preferably use null if it makes more sense.
Note: if you insert data from another source, just use casting to integer in php:
FigureModel::create(array(
'worldwideoffices' => (int) $offices,
'worldwideemployees' => (int) $employees,
));

How to use zend_db_select to update when there is two clause

I want to update an entry in the table when 2 conditions are met.
I have this statement, but it is only for one where condition
$this->dbo->update('mytable', $data, $this->dbo->quoteInto('id= ?', $id));
Instead of just checking where for just "id", i want to check for userid also..
Appreciate any help.
Something similar to this should work as the $where argument will accept and parse an array, reference the _whereExpr() method in Zend_Db_Adapter_Abstract for the code on how the $where arg is processed:
$this->dbo->update('mytable', $data, array('id= ?'=> $id, 'user_id=?'=>$userId));
I'm going to suggest that you may wish to alter you approach and use the save() method of Zend_Db_Table_Row instead of update. Here's an example.
public function saveUser($id, array $userData, $userId = null)
{
//$this->getDbAdapter is a placeholder for your choice of db adapters, I suggest a DbTable model that extends Zend_Db_Table_Abstract
$select = $this->getDbAdapter()->select();
//if userId is not null build a where clause
if (!is_null($userId)) {
$select->where('user_id = ?', $userId);
}
//build where clause for primary key, two where() in select() will be 'AND' use orWhere() for 'OR'
$select->where('id = ?', $id);
//fetch the row you wish to alter
$row = $this->getDbAdapter()->fetchRow($select);
//assign the data to the row, you can update any or all columns
$row->username = $userData[username];
$row->user_id = $userData[user_id];
//ect...
//save the new data to the row, will only update changed coluns
$row->save();
//return the whole for use in other ways, save() typically only returnbs the primary key.
return $row;
}
Yes this method is a little more verbose and maybe a touch more complicated. However as you start bumping up against the limits of 'INSERT' and 'UPDATE', save() can provide some useful functionality.

Is it possible to use sort() on multiple fields in Doctrine 2 ODM?

I am doing a query on a result document in my doctrine mongodb *odm*. There are two indexed fields in the document which I would like to use in sort. I have written something like:
$results = $this->createQueryBuilder('Document\Score')
->sort('finalScore', 'desc')
->sort('date', 'desc')
->getQuery()
->execute();
Here the second sort() function overrides the first one and the designated result is never found.
Thanks in advance for the nice help.
Try this
$qb = $this->createQueryBuilder('Document\Score');
$qb->sort(array(
'finalScore' => 'desc',
'date' => 'desc',
));
$results = $qb->getQuery()->execute();

How to get a Doctrine2 result object as an associative array?

I have a simple entity which is a table holding my user data
and I want to fetch all columns of a specific user as an array and then json_encode them but what I get is an entity object which I will have to use get method for every value. I just want an associative array of my user table values.
The codes I tried and didn't work (returned entity object) are as follows:
1.
$qb = $this->em->createQueryBuilder();
$qb->add('select', 'a')
->add('from', 'Entities\Adminprofile a')
->add('where', 'a.userid = 3333');
$accounts = $qb->getQuery()->getResult();
2.
$account = $this->em->getRepository('Entities\Adminprofile')->findOneBy(
array('userid' => '3333'));
PS: im using z2d2 Project,which is doctrine2 integration into Zend framework.
When you do $accounts = $qb->getQuery()->getResult(); the argument you pass to getResult tells it how to hydrate the result set which is will return.
Array Hydration
If you want arrays, than you should pass the CONSTANT for array hydrations Doctrine\ORM\Query::HYDRATE_ARRAY.
$accounts = $qb->getQuery()->getResult( Doctrine\ORM\Query::HYDRATE_ARRAY );
If you are using findOneBy() then it will always return an entity. Due to the internals of how find works, you cannot tell it to hydrate by any other means other than to return entities.
In this scenario, what you need to do is create a getValues() method inside of your entity which returns an array of your entity, like this:
public function getSimpleValues(){
return array(
'id' => $this->getId(),
'lft' => $this->getLft(),
'rgt' => $this->getRgt(),
'name' => $this->getName(),
'md5Name' => $this->getMd5Name(),
'owner' => $this->getOwner()->getId(),
'etag' => $this->getEtag()
);
}
Hydration API Docs: http://www.doctrine-project.org/api/orm/2.1/namespace-Doctrine.ORM.Internal.Hydration.html
You can also use getArrayResult() as a shortcut to passing in the constant to get an array back:
$accounts = $qb->getQuery()->getArrayResult();
You should use constant containing value 2 and it is inbuilt, you can do it like this at the end part of your query
$qb->getQuery()->getResult( Doctrine\ORM\Query::HYDRATE_ARRAY );
$data = $this->entity->findOneBy(array('key' => $value));
$hydrator = new \DoctrineModule\Stdlib\Hydrator\DoctrineObject($this->_em, $entity_name);
$array = $hydrator->extract($data);