multiple entity type in entity field query - mysql

How to add multiple entity_type and bundles in EntityFieldQuery?
$query->entityCondition('entity_type', 'profile2')
->entityCondition('bundle', 'user_profile');
Is there any way to do like this?
$query->entityCondition('entity_type', array('profile2','user'))
->entityCondition('bundle', array('user_profile','property'));

This isn't possible: https://api.drupal.org/api/drupal/includes%21entity.inc/class/EntityFieldQuery/7
This class allows finding entities based on entity properties (for example, node->changed), field values, and generic entity meta data (bundle, entity type, entity id, and revision ID). It is not possible to query across multiple entity types. For example, there is no facility to find published nodes written by users created in the last hour, as this would require querying both node->status and user->created.

In the official doc:
public EntityFieldQuery::entityCondition($name, $value, $operator = NULL)
where:
$name: 'entity_type', 'bundle', 'revision_id' or 'entity_id'.
$value: The value for $name. In most cases, this is a scalar. For more complex options, it is an array. The meaning of each element in the array is dependent on $operator.
$operator: Possible values:
'=', '<>', '>', '>=', '<', '<=', 'STARTS_WITH', 'CONTAINS': These operators expect $value to be a literal of the same type as the column.
'IN', 'NOT IN': These operators expect $value to be an array of literals of the same type as the column.
'BETWEEN': This operator expects $value to be an array of two literals of the same type as the column.
I guess you forgot the operator!

Related

Perl / DBI query doesn't preserve integer values for JSON output

I can't get this Perl code to return true integer values for integers in the table. The MySQL table columns are correctly specified as integers, yet the JSON output here wraps all query values in quotes. How can I correctly preserve data-types (esp. integers and boolean values) as specified?
use strict;
use warnings;
use DBI;
use JSON;
my $sth = "SELECT id, name, age FROM table";
my $data = $dbh->selectall_arrayref($sth, {Slice => {}});
my $response = encode_json($data);
print $response;
## outputs: {"id":"1","name":"Joe Blodge","age":"42"}
What am I doing wrong here? How can I get this to output the correctly formatted JSON:
{"id":1,"name":"Joe Blodge","age":42}
DBD::mysql returns all results as strings (see https://github.com/perl5-dbi/DBD-mysql/issues/253). Normally Perl doesn't care, encoding to JSON is one of the few times when it matters. You can either use Cpanel::JSON::XS::Type to provide type declarations for your JSON structure:
use Cpanel::JSON::XS;
use Cpanel::JSON::XS::Type;
my $response = encode_json($data, {id => JSON_TYPE_INT, name => JSON_TYPE_STRING, age => JSON_TYPE_INT});
or you can go through and numify the appropriate elements before JSON encoding.
$data->{$_} += 0 for qw(id age);
It is possible to check the type (as indicated by MySQL) of each returned column, if you construct and execute your query using a statement handle then the type will be available as an array in $sth->{TYPE}, but this is pretty complex and may not be reliable.

REGEX for selecting multiple value in string

I need an sql select statement to retrieve 04:30 and test.zip from this string:
{"TIME":"04:30","DATE":"11\/25\/2013","FILENAME":["test.zip"]}
use this \[(.*?)\]
it return value between [ and ]
and for 04:30 use TIME":(.*?),
it return value after "TIME":
Can't you just decode it and use PHP? (assuming you can't change the way it's stored in the db)
<?php
$str = '{"TIME":"04:30","DATE":"11/25/2013","FILENAME":["test.zip"]}';
$o = json_decode($str);
$time = $o->TIME;
$file = $o->FILENAME[0];
var_dump($time); //"04:30"
var_dump($file); //"test.zip"
Regex replaces etc in MySQL require a UDF (user-defined function) mysql-udf-regexp
If none of the above are viable solutions (change DB structure, do it with PHP, use a MySQL UDF), you'll need to get creative. It would require a known, static format of that string, but you could replace some parts and substring others. For example:
SELECT SUBSTRING(REPLACE(`column_name`,'{"TIME":"',''),1,5) AS `time` FROM `table_name`
File is more complex, this example assuming only one filename in the array
SELECT REPLACE(SUBSTRING(`column_name`,LOCATE('"FILENAME":["',`column_name`)+13),'"]}','') AS `file` FROM `table_name`
Those two field selections get 04:30 and test.zip respectively (you can of course use those functions in the same statement, rather than separately like I have, by comma separating them)

How to create a NOT IN where clause Doctrine_Query?

I am developing in symfony 1.4 using Doctrine ORM. I can't create a NOT IN where clause using an array with ids. This is my code:
$results = Doctrine_Query::create()
->from('Asset a')
->where('a.id NOT IN (?)', implode(',', $ids))
->execute();
The sql for this query that is generated is this one:
WHERE (a.id NOT IN ('1,5,6,7,8,9,10,11,12,13,14,15,17,18,20,24,25,26,29,30,28'))
As you can see is treating the array filled with ids like an string. I tried also without the implode of the array but I get this error:
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
The array $ids containing the excluded ids is a plain numeric one.
I can't find out what is the correct syntax for this clause. Thanks
You have to use whereNotIn (old doc but still ok).
$results = Doctrine_Query::create()
->from('Asset a')
->whereNotIn('a.id', $ids)
->execute();

Subquerying in mysql with full-text querying

I am trying to query a database. I already have a file that includes some primary keys out of this whole database. Now I want to filter these primary keys and get only those primary keys which also agree to "other condition". My primary keys are associated to abstracts in the database. The abstracts are full-text indexed. Now I want to consider the abstracts using the given primary keys, look for my "other condition(terms)" in those abstracts and if its present I want to pull their primary keys out(which is going to be same from the file). My "other condition" is another file with a list of terms. I want to get the abstracts that contain those terms within the given primary keys.
My full-text search is something like this:
while(<FILE1>){
$PK = $_;
foreach $foo(#foo){
my $sth = $dbh->prepare(qq{
SELECT value
FROM value_table
WHERE MATCH (column_text_indexed) AGAINST (? IN BOOLEAN MODE)
}) AND primary_key=$PK;
$sth->execute(qq{+"$foo"});
}
}
where $PK is coming from the list of primary keys I already have.
$foo will be the list of the terms (condition 2) I am looking for.
Normally, I can run this query number of $PK times number of $foo. But I learned something about optimization by sub querying where I won't be running my query # $PK times # $foo. That will get rid of inner loop but will still form combination of every $PK with every term in file 2 that is #foo. Something like as follows:
while(<FILE1>){
$PK = $_;
my $sth = $dbh->prepare(qq{
SELECT value
FROM value_table
WHERE MATCH (column_text_indexed) AGAINST (**SUB QUERYING HERE**)
}) AND primary_key=$PK;
$sth->execute(qq{+"$foo"});
}
Just I don't know how to do it. I may be wrong with the syntax. I want to know how to write code for full-text search as well as a subquery. I hope this will be efficient than querying directly the combinations. Any help is greatly appreciated.
I don't think you need to use a subquery. But you can still get rid of the inner loop by combining the match strings.
my $against = join ' ', map {qq/"$_"/} #foo;
while (my $PK = <FILE1>) {
chomp $PK;
my $sth = $dbh->prepare(qq{
SELECT value
FROM value_table
WHERE primary_key = ?
# no '+' so it can match against at least one of the words in the list
AND MATCH (column_text_indexed) AGAINST (? IN BOOLEAN MODE)
});
$sth->execute($PK, $against);
Update
I revised it and have completely removed the query from the loops.
my #primary_keys;
while (my $PK = <FILE1>) {
chomp $PK;
push #primary_keys, $PK;
}
my $PK_list = join ',', map {qq/'$_'/} #primary_keys;
my $against = join ' ', map {qq/"$_"/} #foo;
my $sth = $dbh->prepare(qq{
SELECT value
FROM value_table
# placeholders can only represent single scalar values so $PK_list can't be bound
WHERE primary_key IN ($PK_list)
# no '+' so it can match against at least one of the words in the list
AND MATCH (column_text_indexed) AGAINST (? IN BOOLEAN MODE)
});
$sth->execute($against);
# continue with fetching the rows
...;
Your syntax looks dodgy. I think you meant:
while(<FILE1>){
$PK = $_;
foreach $foo (#foo){
my $sth = $dbh->prepare(qq{
SELECT value
FROM value_table
WHERE MATCH (column_text_indexed)
AGAINST (**SUB QUERYING HERE**)
AND primary_key=$PK }); # '})' after AND clause
$sth->execute(qq{ $foo });
}
}
But why not make $PK an additional argument in this case (and use best practices)? :
while ( my $PK = <FILE1> ) {
chomp $PK; # Remove trailing newline
foreach my $foo ( #foo ) { # Lexical $foo
my $sth = $dbh->prepare( qq{
SELECT value
FROM value_table
WHERE MATCH (column_text_indexed)
AGAINST (**SUB QUERYING HERE**)
AND primary_key=? }); # Extra placeholder
$sth->execute( $foo, $PK );
}
}
If you want efficiency I would recommend to use least database transactions and operations. So in this case I think the best option is to just get the abstract from the database based the primary key and then search for the terms in that abstract by doing simple string search in your pearl or any other standard language code. I am not very sure of the length of your list of terms. But if its possible you can save it in a standard data-structure like array or list. The same operation in database would definitely take lot more time. I am not that good with pearl syntax so I am writing the algorithm.
for all the terms in PK get the abstract as a string variable :
for each term in array/list: find the term in string variable containing abstract. If found add the PK to a new file.
continue with next pk.
if not found then continue next term in array/list.

Doctrine query returns extra field in result

I have a Doctrine query;
$q = Doctrine_Query::create()->select('s.monthly_volume')
->from('SearchVolume s')
->innerJoin('s.Keywords k')
->where('k.group_id = ?',array($group_id));
I just want it to return the monthly_volume value in the result array. It currently returns monthly_volume and id, I don't want it to return the id in result.
Doctrine automatically adds the primary key field to the results in almost every type of hydration mode.
In a case like this where you want a simple array and only have a single field being selected, the answer is the Single Scalar Hydration mode. Use it like this:
$q = Doctrine_Query::create()->select('s.monthly_volume')
->from('SearchVolume s')
->innerJoin('s.Keywords k')
->where('k.group_id = ?');
$monthly_volumes = $q->execute(array($group_id), Doctrine_Core::HYDRATE_SINGLE_SCALAR);
You should find that $monthly_volumes is a simple one-dimensional array containing only the value(s) you wanted.