Doctrine PHPCR-ODM Query Builder selecting document inside specific node - symfony

I have the following nodes:
/
/applications
/applications/1
/applications/1/pages [contains Page documents]
I want to select all Page documents inside the node /applications/1. I used the following to do that (which seems right), but it throws an error:
$qb = $this->dm->createQueryBuilder();
$qb->from()->document('Mango\CoreDomainBundle\Document\Page', 'page');
// I want to select the pages which are a child of /applications/1
$qb->where()->child('/applications/1', 'application');
$qb->getQuery()->execute();
When I execute this, it throws the following error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'n1.id' in 'field list'
This is the SQL query that is send back to the database:
SELECT
n0.id AS n0_id,
n0.path AS n0_path,
n0.parent AS n0_parent,
n0.local_name AS n0_local_name,
n0.namespace AS n0_namespace,
n0.workspace_name AS n0_workspace_name,
n0.identifier AS n0_identifier,
n0.type AS n0_type,
n0.props AS n0_props,
n0.depth AS n0_depth,
n0.sort_order AS n0_sort_order,
n1.id AS n1_id,
n1.path AS n1_path,
n1.parent AS n1_parent,
n1.local_name AS n1_local_name,
n1.namespace AS n1_namespace,
n1.workspace_name AS n1_workspace_name,
n1.identifier AS n1_identifier,
n1.type AS n1_type,
n1.props AS n1_props,
n1.depth AS n1_depth,
n1.sort_order AS n1_sort_order
FROM
phpcr_nodes n0
WHERE
n0.workspace_name = 'mango'
AND n0.type IN ('nt:unstructured' , 'rep:root')
AND (n1.parent = 'applications/1'
AND (EXTRACTVALUE(n0.props,
'count(//sv:property[#sv:name="phpcr:class"]/sv:value[text()="Mango\CoreDomainBundle\Document\Page"]) > 0')
OR EXTRACTVALUE(n0.props,
'count(//sv:property[#sv:name="phpcr:classparents"]/sv:value[text()="Mango\CoreDomainBundle\Document\Page"]) > 0')))
I hope somebody can help me out! Thanks!

Hmm, it looks like I was just dumb :P The alias used as the second argument of the child condition has to be the alias of the document you run the query builder on.
Wrong:
$qb = $this->dm->getRepository('Mango\CoreDomainBundle\Document\Page')
->createQueryBuilder('page');
$qb->where()->child('/applications/456', 'alias_1');
Good
$qb = $this->dm->getRepository('Mango\CoreDomainBundle\Document\Page')
->createQueryBuilder('page');
$qb->where()->child('/applications/456', 'page');
Also, in my case, I had to use descendant rather than child. See http://docs.doctrine-project.org/projects/doctrine-phpcr-odm/en/latest/reference/query-builder-reference.html#descendant
Topic can be closed :)

Related

DynamoDB Java SDK query to match items in a list

I'm trying to use SQL IN clause kind of feature in dynamoDB. I tried using withFilterExpression but I'm not sure how to do it. I looked at similar questions as they were too old. Is there a better method to do this? This is the segment of code I have got. I have used a static List as example but it is actually dynamic.
def getQuestionItems(conceptCode : String) = {
val qIds = List("1","2","3")
val querySpec = new QuerySpec()
.withKeyConditionExpression("concept_id = :c_id")
.withFilterExpression("question_id in :qIds") // obviously wrong
.withValueMap(new ValueMap()
.withString(":c_id", conceptCode));
questionsTable.query(querySpec);
}
I need to pass qID list to fetch results similar to IN clause in SQL Query.
Please refer to this answer. Basically you need to form key list/value list dynamically
.withFilterExpression("question_id in (:qId1, :qId2, ... , :qIdN)")
.withValueMap(new ValueMap()
.withString(":qId1", ..) // just do this for each element in the list in a loop programmatically
....
.withString(":qIdN", ..)
);
Mind there is a restriction on maxItems in 'IN'

Build query with aggregate functions in HAVING clause

I am trying to figure out how to have aggregate functions in the having clause with CakePHP's query builder.
Background: the intent is to correct all rows in a table with compound primary-keys (page-ID and URL) such that each page-ID-group has only one default video. There are some groups with no, and some groups with more than one "default" row, which needs to be corrected. I've figured out all the steps – except for this detail.
This is the query that I'm trying to build.
SELECT
video_page_id, video_url
FROM page_video
WHERE
video_page_id IN (
SELECT video_page_id
FROM page_video
GROUP BY video_page_id
HAVING SUM(video_is_default) < 1
)
AND video_order = 0
;
And this is what I have built:
// sub-select: all groups that have too few defaults.
// Returns list of page-IDs.
$qb = $this->getQueryBuilder();
$group_selection = $qb
->select(array(
'video_page_id',
))
->from('page_video')
->group('video_page_id')
->having(array(
'1 >' => $qb->func()->sum('video_is_default'),
))
;
// sub-select: compound-primary-key identifiers of all rows where
// `video_is_default` has to be modified from `0` to `1`.
// Returns list of two columns.
$qb = $this->getQueryBuilder();
$modifiable_selection = $qb
->select(array(
'video_page_id',
'video_url',
))
->from('page_video')
->where(array(
'video_page_id IN' => $group_selection,
'video_order = 0',
))
;
But then I get this exception: Column not found: 1054 Unknown column '1' in 'having clause'
The crux is the HAVING clause. I basically don't know how to combine the aggregate function with the attribute-value properties of an array. Usually, in order to craft lower/greater-than clauses, you write it like this: array('col1 >' => $value). But here, I needed to flip the equation because the complex expression can't fit into an array key. And now the 1 gets interpreted as a column name.
Writing it as a concatenated string doesn't seem to help either.
array(
$qb->func()->sum('video_is_default') .' > 1',
)
Exception: PHP Recoverable fatal error: Object of class Cake\Database\Expression\FunctionExpression could not be converted to string
I know I could do …
SELECT (…), SUM(video_is_default) AS default_sum FROM (…) HAVING default_sum < 1 (…)
… but then the sub-select column count doesn't match anymore.
Exception: ERROR 1241 (21000): Operand should contain 1 column(s)
I feel silly for figuring out the solution so soon after asking the question.
The lt method acccepts complex values as the first parameter.
->having(function($exp, $qb) {
$default_sum = $qb->func()->sum('video_is_default');
return $exp->lt($default_sum, 1);
})

How to write/extend custom DQL Function for Cast(X $comparisonOperator Y) in Doctrine? (Goal: Show related Objects)

To show related Articles on a website, I need the Cast() function.
My Query looks like:
SELECT
*,
(CAST(a.uploader = ?1 AS UNSIGNED)
+ CAST(a.param2 = ?2 AS UNSIGNED)
...
) AS matches_count
FROM articles AS a
ORDER BY matches_count DESC
It counts the matches and sorts by the highest number of matches_counts.
The problem is, that there's no Cast() function built into doctrine.
After hours of trial and error I found an already available custom DQL Function:
https://github.com/beberlei/DoctrineExtensions/blob/master/src/Query/Mysql/Cast.php
I registered it inside my doctrine.yml.
But it doesn't work, because it expects Cast(X AS Y) and not Cast(Y $comparisonOperator X).
When I'am using this inside my repository, by example:
$this->createQueryBuilder('a, (CAST(author=25 AS UNSIGNED) AS matches_count)')
->getQuery()
->getResult()
;
I get this error, because it doesn't expect a comparison operator:
[Syntax Error] line 0, col 29: Error: Expected Doctrine\ORM\Query\Lexer::T_AS, got '='
Do you know how to maybe extend that class for and not Cast(Y $comparisonOperator X) instead of Cast(X AS Y)?
I didn't find any solution on the internet and tried it for hours.
Thank you in advance for taking the time to write an answer!
Update:
I changed line 37 in the above mentioned custom DQL class for Cast:
//old
//$this->fieldIdentifierExpression = $parser->SimpleArithmeticExpression();
//new
$this->fieldIdentifierExpression = $parser->ComparisonExpression();
and how to create the query:
$this->createQueryBuilder('a')
->select('a, (CAST(a.averageRating=:averageRating AS UNSIGNED) + CAST(a.author=:author AS UNSIGNED)) AS matches_count')
->setParameter('averageRating', $averageRating)
->setParameter('author', $author)
->orderBy('matches_count', 'DESC')
->getQuery()
->getResult();
and that seems to be it!
I hope its the right way of doing it, will help someone and that is the best way for this purpose.
To improve performance later, I plan to cache 10 ids of recommended articles for every single article page into its own table.
So it doesn't need to do the calculation on page load.
This table could get recreated every 24h via a cronjob.
ID | recommended_article_ids | article_id
1 | 10,24,76,88| 5
Feedback and tips are much appreciated!

DRUPAL error PDOException: SQLSTATE[42S22]:

can someone help me to fix this
Additional uncaught exception thrown while handling exception.
Original
PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'base.owner' in 'field list': SELECT base.id AS id, base.name AS name, base.label AS label, base.plugin AS plugin, base.active AS active, base.weight AS weight, base.status AS status, base.dirty AS dirty, base.module AS module, base.owner AS owner, base.access_exposed AS access_exposed, base.data AS data FROM {rules_config} base WHERE (base.plugin = :db_condition_placeholder_0) AND (base.active = :db_condition_placeholder_1) ; Array ( [:db_condition_placeholder_0] => reaction rule [:db_condition_placeholder_1] => 1 ) in EntityAPIController->query() (line 187 of /home/tjmcom/public_html/mydomain. com/sites/all/modules/entity/includes/entity.controller.inc).
Additional
PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'base.owner' in 'field list': SELECT base.id AS id, base.name AS name, base.label AS label, base.plugin AS plugin, base.active AS active, base.weight AS weight, base.status AS status, base.dirty AS dirty, base.module AS module, base.owner AS owner, base.access_exposed AS access_exposed, base.data AS data FROM {rules_config} base WHERE (base.plugin = :db_condition_placeholder_0) AND (base.active = :db_condition_placeholder_1) ; Array ( [:db_condition_placeholder_0] => reaction rule [:db_condition_placeholder_1] => 1 ) in EntityAPIController->query() (line 187 of /home/tjmcom/public_html/mydomain. com/sites/all/modules/entity/includes/entity.controller.inc).
This sounds like a problem with the Rules Project not having completed its update. Put your site in maintenance mode and go to yoursite.com/update.php.
This issue is documented at https://www.drupal.org/project/rules/issues/2094879 and comment #45 gives a checklist of items to do. If that does not work, please confirm you're indeed using Rules in your setup, and what version you're running.
Furthermore, if you have unsuccessfully tried any specific steps to resolve this issue and it persists, describe briefly what they were. It'll save time to getting you on the right path, avoiding describing suggestions you already tried. (You'll find tips on how to receive quicker and better answers over at https://stackoverflow.com/questions/how-to-ask.)
Welcome to StackOver flow.

LINQ: Get all members with LAST order failed

I'm learning LINQ, and I'm trying to figure out how to get all members with the last order failed (each member can have many orders). For efficiency reasons I'd like to do it all in LINQ before putting it into a list, if possible.
So far I believe this is the right way to get all the members with a failed order which joined recently (cutoffDate is current date -10 days).
var failedOrders =
from m in context.Members
from o in context.Orders
where m.DateJoined > cutoffDate
where o.Status == Failed
select m;
I expect I need to use Last or LastOrDefault, or possibly I need to use
orderby o.OrderNumber descending
and then get the First or FirstOrDefault as suggested in this stackoverflow answer.
Note that I want to look at ONLY the last order for a given member and see if that has failed (NOT just find last failed order).
Normally you would write something like:
var failedOrders = from m in context.Members
where m.DateJoined > cutoffDate
select new
{
Member = m,
LastOrder = m.Orders.OrderByDescending(x => x.OrderNumber).FirstOrDefault()
} into mlo
// no need for null checks here, because the query is done db-side
where mlo.LastOrder.Status == Failed
select mlo; // or select mlo.Member to have only the member
This if there is a Members.Orders relationship

Resources