ColdFusion: get amount of results from a query - coldfusion

I have some ColdFusion output:
<cfoutput query="myList">#Email#</cfoutput>
If my list happens to have several results, this output loops and prints out all the emails. However, if there are no results, I would like to write a statement to output a message...
How does this work? It seems like #Email# is a variable, but it can also be an array...how do I count the number of results when using like this?
update: I have also tried using a stored procedure to do a COUNT, which gives me the amount...but I'm not sure how to use the results of the stored procedure in a coldfusion <cfif> statement...

<cfif myList.RecordCount>
<cfoutput query="myList">#Email#</cfoutput>
<cfelse>
No results
</cfif>
is what you are looking for, and is the strategy most commonly employed by ColdFusion developers.

A Query is a Coldfusion-specific datatype that looks like an array of structs but behaves differently.
You can check for the number of records as #myList.recordcount#
<cfif not myList.recordcount>
No records found
</cfif>

Related

Easy way to check ColdFusion range then select a value if outside of that range

I'm new to ColdFusion, and I came across some legacy code that wasn't checking a GET parameter for a number. I'm trying to add some code similar to:
<cfparam name="URL.count"
default="5"
min="1" max="9999"
type="range">
Such that nobody can just add arbitrary values like 50,000 or -1. I thought, that ColdFusion would use the specified default value if it was outside that range, but instead it appears to throw an exception and use the default only when nothing is specified.
I can try/catch the exception, but I was wondering, since I'm new to this, if there wasn't a better practice in ColdFusion for handling a situation like that. Perhaps there is another ColdFusion tag I don't know about—that sorta thing.
The practice for handling this in ColdFusion is the same as it is in any language - if/else.
if (url.count <= 99999) {
code for good count
}
else {
code for bad count
}
Now, since this is a url variable, it might be the case where you have control over that as well. If it's coming from a form method="get", you can add some client side validation to augment, not replace the server side validation shown above.
Similarly, if it's coming from an anchor tag or cflocation tag that you generated, you can do something when generating that code to prevent the situation.
CFPARAM is just used to set a default value for a variable if it has not already been defined. While it can be used to validate the data type of a variable, it can't perform conditional logic related to values. You have to do that manually.
<cfparam name="URL.count" type="numeric" default="5">
<cfif (url.count LT 1) OR (url.count GT 9999)>
<cfthrow type="error" message="The current count (#url.count#) is outside of the allowed range.">
</cfif>
Combine Min and Max, like so. I'd be more verbose but I think it only makes it confusing. (minimum between maximum between and...)
Min(Max(lower_boundary,currentnumber),upperBoundary)
As a function, more readable,
<cfscript>
numeric function uForceRange(required numeric cNum, required numeric lNum, required numeric hNum) {
return Min(Max(arguments.lNum,arguments.cNum),arguments.hNum);
}
</cfscript>
<cfoutput><pre>Between 1 and 10:
7: #uForceRange(7,1,10)#
0: #uForceRange(0,1,10)#
42: #uForceRange(42,1,10)#
10.4: #uForceRange(10.4,1,10)#</pre></cfoutput>
This simple function is of course implemented just as easily in any language.

How to store time shown by cftimer in a variable?

I want to store the time taken by a code to execute in a coldfusion variable.
There is a tag called cftimer that displays the time taken by a code to execute.
Is there a way to store the time displayed by cftimer tag in a variable?
Use
<cfset var startTicks = GetTickCount() />
<!--- code to benchmark --->
<cfset var ticksTaken = GetTickCount() - startTicks />
for better control. Note that ticks are ms, and irrelevant unless diffing (the absolute value has no meaning).
As Adam and MaxH have stated, you'll want to use getTickCount() to time a script.
getTickCount() isn't just for troubleshooting, you can do a lot of cool stuff with it. If you want you can also do this inside your onRequest function to time all of your scripts and react to a long script if needed.
<cffunction name = "onRequest">
<cfargument name = "targetPage" ...>
<cfset startTime = getTickCount()>
<cfinclude template = "#arguments.targetPage#">
<cfset processTime = getTickCount()-startTime>
<cfif structKeyExists(url,"showTime")>
<cfoutput>The page took #processTime# milliseconds to process</cfoutput>
</cfif>
<!--- you could also do other stuff like record processing times to a db or send alerts if processTime > somevalue --->
</cffunction>
I have one project that depends on a lot of external data which is subscribed to by the customer. I save all the processing times for the individual processes into a session structure so I can see if it's me or one of the 3rd party web services that are causing the slow down. If one of the web services bogs down I alert the customer so they can decide if they want to choose a different service.
If you can, it would be tricky to do, and trying to take a square peg out of a round hole. However what you can easily use getTickCount() to take the... well... the tick count before and after the operation, and the difference between the two is your duration. Which you can then do with what you want.

Why would order of search terms affect solr query results?

If I search for Authorname "Title of Work" the records don't come up, but if I search for "Title of Work" Authorname then they do.
Why might this happen?
This is solr running on Coldfusion. The only change is the order of the terms.
Update
Sample coldfusion code. Note that in this example first one gets 2 matches while the second one gets 1. So it looks like this changes depending on the actual string searched, but it still means that changing the order of terms changes the number of records returned.
I could understand it changing the order of records returned, since changing the order would change the relevance of the results. But all 3 records should show up for either one. I'll see if I can find the solr logs and post them, that might help.
<cfset term1='"globalization of information"'>
<cfset term2='Reiter'>
<cfsearch name="ExampleOne" criteria='#term1# #term2#' collection="abstracts,fulltexts">
<cfoutput>#ExampleOne.recordcount#</cfoutput>
<cfsearch name="ExampleTwo" criteria='#term2# #term1#' collection="abstracts,fulltexts">
<cfoutput>#ExampleTwo.recordcount#</cfoutput>
<cfabort>
Output:
2 1
Just try giving search term in single quotes, I have tested in on CF 10 and it is working fine for me.
So Instead of:
cfset term1='"globalization of information"'
try this
cfset term1="'globalization of information'"

Getting values from CFLOOP

I am trying to pull out values from a CFLOOP and dump them but I seem to be missing something.I need to extract openHours from the first loop and openMinutes from the second and put them in variables that will then run a query for submitting the values in the database.
This is my struct when I dump out #form#. I need to get the variable form.openHours1 the problem is that openHours gets its number by #CountVar# so basically i need to dump out something like #form.openHours[CountVar]#
struct
FIELDNAMES POSTITNOW,OPENHOURS1,OPENHOURS2,OPENHOURS3,OPENHOURS4,OPENHOURS5,OPENHOURS6,OPENHOURS7
OPENHOURS1 13
OPENHOURS2 13
OPENHOURS3 12
OPENHOURS4 0
OPENHOURS5 0
OPENHOURS6 0
OPENHOURS7 0
POSTITNOW YES
Rather than #form.openHours[CountVar]# what you want is:
form["openHours" & CountVar]
As a scope, FORM is also a struct and you can use array notation to get at the values.
This is key for working with dynamic form field names.
To clarify:
form.openHours7
is equivalent to
form["openHours7"]
The first is generally known as dot-notation, the second as array-notation (since it resembles how you refer to array elements.
Since the value in the bracket is a string, you can replace it with a variable.
<cfset fieldToUse = "openHours7">
<cfoutput>#form[fieldToUse]#</cfoutput>
Or, as I opened with, a combination of a literal string and a variable.
You can't really do that with dot-notation. (At least not without using evaluate(), which is generally not recommended.)
The documentation has lots of information on how to work with structures, including the different notation methods.
I think you want this, or something very similar:
<cfoutput>
<cfloop from="1" to="7" index="CountVar">
#openHours[CountVar]#<br>
</cfloop>
</cfoutput>
Sorry, this is a little murky to me, but that's never stopped me from jumping in. Are you going to have an equal number of openhours and openminutes? Can you just loop over form.fieldnames? As it stands now, you have fields named openhours1-N, it sounds like openminutes1-N is yet to be added. It seems that you could loop over fieldnames, if the field starts with openhours you get the number off the end and then you can easily create the corresponding openminutes field. As Al said (much) earlier, you would then most likely use array-notation to get the values out of the form structure.
Another thought is that form field names don't have to be unique. If you had multiple occurrences of "openhours", ColdFusion would turn that into a list for you, then you could just loop over that list.

Is there a limit on how long a cfquery with cfqueryparam can get?

I have some code that does a tight loop to insert thousands+ records and recently when I introduce <cfqueryparam>, CF crashes.
Something like...
<cfquery>
<cfloop query="qBars">
INSERT INTO Foo
SET
xx = <cfqueryparam value="#qBars.aa#" sqltype="CF_SQL_VARCHAR">,
yy = <cfqueryparam value="#qBars.bb#" sqltype="CF_SQL_INTEGER">
</cfloop>
</cfquery>
This used to work beautifully without <cfqueryparam>. With cfqueryparam however, I guess it might be problematic when the recordcount of qBars is large (10,000+).
Now... What shall I do? Refactor the whole thing to be handled in DB level?
Thanks
To be honest, if I was needing to load 10k+ records into the DB, I would not use CFQUERY. Your DB will almost certainly have the capability to bulk load data, so I recommend investigating that.
I think the maximum number of bind parameters allowed would be a restriction set by the DB engine rather than by CF or the underlying JDBC. But you don't mention which DB you're using, so it's hard to research an answer for you there.
I did some snooping around and found this table for SQL Server: http://msdn.microsoft.com/en-us/library/ms143432.aspx. It does not specifically mention how many bind params an inline query can have, but the figure of 2100 they mention for params for a proc or function is the same as the maximum number of parameters I've been able to pass in a list before (like for a WHERE IN clause). I always thought it was the maximum size for a list, but perhaps it's actually the cut off for how many params in general. This would be easy for you to test... try your loop with 1005 iterations and see if it works. Then try it with 1006 iterations, and me might expect it to fail.
That is, of course, if you happen to be on SQL Server...
Also, you say the thing crashes, but you don't say what the error is... it's always helpful to include this sort of information when you're asking this sort of question.
Antony has a good suggestion... I would check to see what impact this has on your problem. Personally, I'd lean towards refactoring. I've had great success in moving data intensive operations to the database level.
I'm currently responsible for an application that parses and analyzes keywords. The parser was originally written in coldfusion, which worked great. As the volume of entries to process grew (almost exponentially), the process itself became very slow. I rewrote the code in t-SQL (I'm running SS2K8) and the response time increased substantially. imho, refactoring is worth the time, especially on data intensive operations.
I would change the code to
<cfloop query="qBars">
<cfquery>
INSERT INTO Foo
SET
xx = <cfqueryparam value="#qBars.aa#" sqltype="CF_SQL_VARCHAR">,
yy = <cfqueryparam value="#qBars.bb#" sqltype="CF_SQL_INTEGER">
</cfquery>
</cfloop>
And see what happens. If that works, you can wrap a <cftransaction around the whole thing which will send all the inserts in one transaction rather than thousands.
You could also try:
INSERT INTO ''foo'' (''xx'',''yy'')
VALUES 
<cfloop query="qBars">
(<cfqueryparam value="#qBars.aa#" sqltype="CF_SQL_VARCHAR">, <cfqueryparam value="#qBars.bb#" sqltype="CF_SQL_VARCHAR">)
<cfif NOT qBars.currentRecordcount eq qBars.recordcount>,</cfif>
</cfloop>
I think this will work. I have not tried it recently, but I am pretty sure I have used it in the past. I modified this example for another SO answer.