Active Record Query where value in array field - ruby-on-rails-3

I have a table called " Stat " in my MongoDB database in Rails 3 .
In that table, there is an array field called "services" .
I want to find all Stats that have a services array that contains the value "lights" .
I want to do something like this :
#stats = Stat.all
#stats1 = #stats.where("services contains lights")
Rails.logger.info "result: #{#stats1.count} "
I've tried various things and Googled it extensively, found some leads but nothing that seems to work. I have four records that should match this query but the above returns a zero set.
Is what I want to do possible in rails 3 / mongo ?

Try this,
#stats = Stat.all
#stats1 = #stats.where("'lights' = ANY (services)")

Ok I found the answer to this question:
#stats = #stats.where(:services.in =>['lights'] )
and I also found by poking around that the inverse is:
#stats = #stats.where(:services.nin =>['lights'] )
nin instead of in

Related

cfsavecontent display double apostrophe in SQL statement

I have several OR in my SQL statement so I want to save a chuck of it in a cfsavecontent. Here is that part:
<cfsavecontent variable="checkDepartment">
<cfif #wrkDept# EQ #dept[2][1]#>
Department = 'Health' AND
<cfelse>
Department = '#wrkDept#' AND
</cfif>
</cfsavecontent>
But the error I get on the page shows 2 sets of apostrophes around the word Health.
SQL
SELECT COUNT(*) AS numItems
FROM IT_PROJECTS
WHERE
Department = ''Health'' AND
status = 'Cancelled'
Can anyone help me to only get a single apostrophe? Thanks
So this answer seems a lot more complicated than it really is. And without knowing specifically what your query looks like (re:OR conditions), I'm not really sure how to structure it. It can be better. The goal should be to make one single trip to your SQL server with the query that makes the most sense for the data you're trying to get. I'm not sure what you are trying to do with cfsavecontent, but I don't think you need it.
The bulk of my example query (https://trycf.com/gist/4e1f46bfa84a6748aced0f9ee8221c6d/acf2016?theme=monokai) is setup. I chose to go with a cfscript format, because as Redtopia said, I also find it much easier to build a dynamic query in cfscript.
After initial setup, I basically just script out the variables I'll use in my final queryExecute().
// Base query.
qry = "SELECT count(*) AS theCount FROM IT_PROJECTS WHERE 1=1 " ;
// This is our dynamic filter that we build below.
qfilter = {} ;
// Query options.
opts = { "dbtype":"query" } ;
After we have our base, I build up the dynamic part of the query. This is the part that will likely change quite a bit depending on your current needs and setup.
For the first part, I basically replaced your cfif with a ternary evaluation. I'm not sure how your data plays into the evaluation of dept or where that array comes from. But from there I build a basic included statement of the query and set up the queryparam values for it. Then I add a second check that will pick a different set of values for the query (currently based on even/odd seconds). Again, I'm not sure of the intent of your query here, so I just made something dynamic.
//////////// BUILD DYNAMIC FILTER ////////////
qdept = ( wrkDept == dept[2][1] ) ? 'Health' : wrkDept ;
/// This one is an included filter:
qry &= " AND department = :dpt AND status = :sts " ;
qfilter.dpt = {"value":qdept,"cfsqltype":"CFSQLVARCHAR"} ;
qfilter.sts = {"value":"Cancelled","cfsqltype":"CFSQLVARCHAR"} ;
/// Adding Dynamic ORs
// Dynamically set status based on even/odd seconds.
qStatus = ( now().second()%2==0) ? "Cancelled" : "Active" ;
qry &= " OR ( department = :dpt2 AND status = :sts2 ) " ;
qfilter.dpt2 = {value:"IT",cfsqltype:"CFSQLVARCHAR"} ;
qfilter.sts2 = {value:qStatus,cfsqltype:"CFSQLVARCHAR"} ;
This gives us a SQL string that looks like:
SELECT count(*) AS theCount
FROM IT_PROJECTS
WHERE 1=1
AND department = :dpt AND status = :sts
OR
( department = :dpt2 AND status = :sts2 )
With a SQL statement, the placement of AND and OR conditions can greatly impact the results. Use parenthesis to group conditions how you need them.
After we've built the query string, we just have to plug it and our queryparams into the queryExecute().
result = queryExecute( qry , qfilter , opts ) ;
And if we want to output our data, we can go:
writeOutput("There are " & result.theCount & " records." ) ;
Which gives us:
There are 8 records.
Again, I don't know what your main conditions look like. If you can give me an example of a query with a bunch of ORs and ANDs, I'll try to modify this for you.

django using .extra() got error `only a single result allowed for a SELECT that is part of an expression`

I'm trying to use .extra() where the query return more than 1 result, like :
'SELECT "books_books"."*" FROM "books_books" WHERE "books_books"."owner_id" = %s' % request.user.id
I got an error : only a single result allowed for a SELECT that is part of an expression
Try it on dev-server using sqlite3. Anybody knows how to fix this? Or my query is wrong?
EDIT:
I'm using django-simple-ratings, my model like this :
class Thread(models.Model):
#
#
ratings = Ratings()
I want to display each Thread's ratings and whether a user already rated it or not. For 2 items, it will hit 6 times, 1 for the actual Thread and 2 for accessing the ratings. The query:
threads = Thread.ratings.order_by_rating().filter(section = section)\
.select_related('creator')\
.prefetch_related('replies')
threads = threads.extra(select = dict(myratings = "SELECT SUM('section_threadrating'.'score') AS 'agg' FROM 'section_threadrating' WHERE 'section_threadrating'.'content_object_id' = 'section_thread'.'id' ",)
Then i can print each Thread's ratings without hitting the db more. For the 2nd query, i add :
#continue from extra
blahblah.extra(select = dict(myratings = '#####code above####',
voter_id = "SELECT 'section_threadrating'.'user_id' FROM 'section_threadrating' WHERE ('section_threadrating'.'content_object_id' = 'section_thread'.'id' AND 'section_threadrating'.'user_id' = '3') "))
Hard-coded the user_id. Then when i use it on template like this :
{% ifequal threads.voter_id user.id %}
#the rest of the code
I got an error : only a single result allowed for a SELECT that is part of an expression
Let me know if it's not clear enough.
The problem is in the query. Generally, when you are writing subqueries, they must return only 1 result. So a subquery like the one voter_id:
select ..., (select sectio_threadrating.user_id from ...) as voter_id from ....
is invalid, because it can return more than one result. If you are sure it will always return one result, you can use the max() or min() aggregation function:
blahblah.extra(select = dict(myratings = '#####code above####',
voter_id = "SELECT max('section_threadrating'.'user_id') FROM 'section_threadrating' WHERE ('section_threadrating'.'content_object_id' = 'section_thread'.'id' AND 'section_threadrating'.'user_id' = '3') "))
This will make the subquery always return 1 result.
Removing that hard-code, what user_id are you expecting to retrieve here? Maybe you just can't reduce to 1 user using only SQL.

sql to set an xml value

I'm a novice in mySql.
I'm trying to replace a value in the xml column of my table.
my select method works.
SELECT * FROM `comics` WHERE ExtractValue(xml,'comic/pageNumber') = 6
my replace method doesn't. I've been searching for the correct syntax for a bit now...
SET xml.modify(
replace value of ('comic/pageNumber') with 5
)
some background:
this situation comes up when i delete a comic page.
it leaves a gap in the page numbers, after which i would either:
iterate through all the comics and remove any gaps in the page numbers.
or
iterate through all comics with pageNumber larger than the deleted page, and reduce their pageNumber by 1.
How about
UPDATE comics
SET xml = UpdateXML(xml,'comic/pageNumber', '<pageNumber>5</pageNumber>')
WHERE ExtractValue(xml,'comic/pageNumber') = 6
Tested on MySQL version 5.1
UPDATE `comics`
SET xml = UpdateXML(xml,
'comic/pageNumber',
concat('<pageNumber>',(ExtractValue(xml,'comic/pageNumber')+1),'</pageNumber>'))
WHERE ExtractValue(xml,'comic/pageNumber') >= 1
You'd be better off actually storing the fields in the table, rather than a single field with xml in it. Then the following would work. Otherwise there's not much point using a relational database at all.
BEGIN;
DELETE FROM `comics`
WHERE `comicID` = :id AND `pageNumber` = :page;
UPDATE `comics` SET `pageNumber` = `pageNumber` - 1
WHERE `comicID` = :id AND `pageNumber` > :page;
COMMIT;

(drupal)a difficulty code to understand,get the same article's title under the same term

if ($node->taxonomy) {
$query = 'SELECT DISTINCT(t.nid), n.nid, n.title FROM {node} n INNER JOIN {term_node} t ON n.nid = t.nid WHERE n.nid != %d AND (';
$args = array($node->nid);
$tids = array();
foreach ($node->taxonomy as $term) {
$tids[] = 't.tid = %d';
$args[] = $term->tid;
}
$query .= implode(' OR ', $tids) . ')';
$result = db_query_range($query, $args, 0, 10);
while ($o = db_fetch_object($result)) {
echo l($o->title, 'node/' . $o->nid);
}
}
the code is from a drupal guru. . used to get the article's title under the same term in node.tpl.php, i have researched it two days, although know some part of it. the principle of the code i still don't know. expect someone can explain more details about it for me .many thanks.
Short version:
It gets the array of tags of the node, retrieves the first 10 nodes that use at least one of these tags and outputs a link for each of these 10 results.
Detailed version:
First of all, the variable "$node" is an object that contains the data about a specific node (e.g. a Page or Story node).
For example, "$node->title" would be the title of that node.
"$node->taxonomy" tests is that node is tagged (because if it has no tags, it cannot retrieve the other nodes using the same tag(s).
When there is one or several tags associated with that node/page/story, $node->taxonomy is an array .
Now about the SQL query:
"node" is the database table that stores the base fields (non-CCK) of every node.
"term_node" is the database table that contains the combination of tag (which is called a "taxonomy term") and node.
In both tables, "nid" is the "unique Node ID" (which is an internal autoincremented number). Because this column is in both tables, this is how the tables are joined together.
In "term_node", "tid" is the "unique Term ID" (which is also an internal autoincremented number).
The "node" table is aliased "n", therefore "n.nid" means "the Node ID stored in table node".
The "term_node" table is aliased "t", therefore "t.tid" means "the Term ID stored in table term_node".
The "foreach" loop goes thru the array of tags to extract the TermID of each tag used by the node in order to add it in the SQL query, and implode converts to a string.
The loop stores a piece of SQL query for each tag in variable $tids and stores the actual value in variable $args because Drupal database calls are safer when the arguments are passed separately from the SQL query: "%d" means "integer number".
"db_query_range" is a function that selects multiple rows in the database: here, "0 10" means "retrieve the first 10 results".
"db_fetch_object" in the "while" loop retrieves each result and stores it in the variable "$o", which is an object.
Therefore "$o->title" contains the value of the column "title" retrieved by the SQL query.
The function "l" is the drupal functin that creates the code for an HTML link: the first argument is the name of the link, the second argument is the drupal path: in Drupal, any node can be accessed by default using "www.yoursite.com/node/NodeID",
which is why it gives the path "node/123" (where 123 is the "Node ID").
This function is useful because it transparently handles custom paths, so if your node has a custom path to access it using "www.yoursite.com/my-great-page" instead, it will create a link to that page instead of "www.yoursite.com/node/123" automatically.
I wouldn't exactly call the guy who wrote this a guru, you could do this a lot prettier. Anyways what he does it create a query that looks like this:
SELECT DISTINCT(t.nid), n.nid, n.title FROM {node} n
INNER JOIN {term_node} t ON n.nid = t.nid
WHERE n.nid != %d
AND (t.tid = %d OR t.tid = %d OR ... t.tid = %d);
The end result is that he selects all the node ids and titles (only once) that share at least one term with the selected node, but isn't the node itself.

Merging result from 2 columns with same name and not over-writing one

I have a simple MySQL query like:
SELECT *
FROM `content_category` CC , `content_item` CI
WHERE CI.content_id = '" . (int)$contentId . "'
AND CI.category_id = CC.category_id
AND CI.active = 1
Both tables have a column called configuration one of which gets overwritten in the query i.e only content_item.configuration is returned in the result.
Short of implicitly naming and aliasing the columns like
SELECT CC.configuration as `category_configuration`,
CC.category_id as `.....
is there a way of selecting ALL data i.e * from both and resolve those duplicate column names in a non-destructive way.
You don't need to alias ALL the columns, just the one conflicting one:
SELECT *,CC.configuration as cc_conf, CI.configuration as ci_conf FROM `content_category` CC , `content_item` CI WHERE
CI.content_id = '" . (int)$contentId . "'
AND CI.category_id = CC.category_id
AND CI.active = 1
This demonstrates one of the many reasons why using the * wildcard is not a good practice all the time. All the columns are returned in the result set, but if you access them via an associative array or via object properites in your host language (e.g. PHP or Ruby) you can naturally only have one of the columns associated with each key or object property.
Solutions:
Fetch them all and reference the columns by ordinal position.
Stop using the wildcard for one table or the other, and give column aliases.
Rename your columns to be distinct.
Define a VIEW with the column aliasing spelled out, and query from the view.