Why Document DB procedure returns only 100 docs on querydocument? - stored-procedures

I have below procedure in Document DB. It executes fine from DocumentDb script explorer but the result it returns is partial. I have more than 250 documents satisfying its given where clause which I checked in query explorer. But when I run procedure from script explorer count(defined in procedure) is always 100.
Below is my procedure -
function getInvoice(pageNo, numberOfRecords, member, searchText, customerGroupId,ResellerId) {
var collectionReseller = getContext().getCollection();
var filterquery ;
var count=0, invoiceAmountTotal=0, referalCommissionTotal=0, developerCommissionTotal=0;
var customerIdString='';
var InvoiceList = [];
var whereClause;
if (customerGroupId != "") {
filterquery = 'SELECT c.id from c where c.Type="Customer" and c.CustomerGroupID="' + customerGroupId + '"';
var isAccepted = collectionReseller.queryDocuments(
collectionReseller.getSelfLink(), filterquery,
function (err, documents, responseOptions) {
var docCount = documents.length;
documents.forEach(function (doc) {
docCount--;
if (docCount > 0)
customerIdString = customerIdString + '"' + doc.id + '", '
else
customerIdString = customerIdString + '"' + doc.id + '" '
})
whereClause = 'where r.Type="Invoice" and r.CustomerID IN (' + customerIdString + ')'
var filterquery1 = 'SELECT * FROM root r ';
if (member.length > 0) {
member.forEach(function (val, i) {
whereClause = whereClause + ' and contains(r.' + member[i] + ',"' + searchText[i] + '")';
});
}
isAccepted = collectionReseller.queryDocuments(
collectionReseller.getSelfLink(), filterquery1 + whereClause,
function (err, invoiceDoc) {
var qr = filterquery1 + whereClause;
count = invoiceDoc.length;
invoiceDoc.forEach(function (doc) {
invoiceAmountTotal = parseFloat(invoiceAmountTotal) + parseFloat(doc.InvoiceAmount);
referalCommissionTotal = parseFloat(referalCommissionTotal) + parseFloat(doc.ReferralCommission);
developerCommissionTotal= parseFloat(developerCommissionTotal) + parseFloat(doc.DeveloperCommission);
InvoiceList.push(doc);
});
InvoiceList.sort(SortByID);
InvoiceList = InvoiceList.slice(pageNo * numberOfRecords, pageNo * numberOfRecords + numberOfRecords);
// Check the feed and if empty, set the body to 'no docs found',
// else take 1st element from feed
getContext().getResponse().setBody(JSON.stringify({ InvoiceList, count, invoiceAmountTotal, referalCommissionTotal, developerCommissionTotal }));
});
});
}
else
{
whereClause = ' where r.Type = "Invoice" and r.ResellerID = "'+ ResellerId + '"';
filterquery = 'SELECT * FROM root r ';
if(member.length > 0) {
member.forEach(function (val, i) {
whereClause = whereClause + ' and contains(r.' + member[i] + ',"' + searchText[i] + '")';
});
}
filterquery = filterquery + whereClause;
var isAccepted = collectionReseller.queryDocuments(
collectionReseller.getSelfLink(), filterquery,
function (err, documents, responseOptions) {
if (err) throw err;
invoiceDoc = documents;
count =invoiceDoc.length;
invoiceDoc.forEach(function (doc) {
InvoiceList.push(doc);
invoiceAmountTotal = parseFloat(invoiceAmountTotal) + parseFloat(doc.InvoiceAmount);
referalCommissionTotal = parseFloat(referalCommissionTotal) + parseFloat(doc.ReferralCommission);
developerCommissionTotal= parseFloat(developerCommissionTotal) + parseFloat(doc.DeveloperCommission);
});
InvoiceList.sort(SortByID);
InvoiceList = InvoiceList.slice(pageNo * numberOfRecords, pageNo * numberOfRecords + numberOfRecords);
// Check the feed and if empty, set the body to 'no docs found',
// else take 1st element from feed
getContext().getResponse().setBody(JSON.stringify({ InvoiceList, count, invoiceAmountTotal, referalCommissionTotal, developerCommissionTotal }));
});
}
function SortByID(a, b) {
var aName = a.UpdatedOn.toLowerCase();
var bName = b.UpdatedOn.toLowerCase();
return ((aName < bName) ? -1 : ((aName > bName) ? 1 : 0));
}
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Any help will be highly appreciated..

If you want to get all 250 back in one shot, you need to populate the options parameter for queryDocuments() with a pageSize field. It's an optional third parameter for that function call. Without it, this server-side API will default to 100.
You can also set pageSize to -1 to get you all documents. However, for server-side stored procedures, I recommend against this. Rather, you need to handle paging using the continuation token. If you want it to be really robust you also need to deal with premature shutdown of the stored procedure.

Related

Optimized approach for Snowfake table search for string/list of strings from Java API

I need to search for string or list of strings Snowflake table using Java API and fetch all the matching rows and display in Angular UI. I am using dynamic SQL (like operator) to generate the query using information schema. I have created this stored procedure and its working. Do we have any better approach or any architectural patterns for this particular usecase.
Based on the search option (starts/ends with) decide the start and end character to be used with Like operator
Get all the varchar,char columns from the table by joining with information schema.
Build dynamic sql with these columns.
Build the json array based on the query result.
CREATE OR REPLACE PROCEDURE SEARCH_DATA(SCHEMA_NAME VARCHAR, TABLE_NAME VARCHAR, SEARCH_OPTION VARCHAR, KEYWORDS ARRAY)
RETURNS VARIANT
LANGUAGE JAVASCRIPT
EXECUTE AS OWNER
AS '
var searchStart = "";
var searchEnd = "";
if (SEARCH_OPTION == "Starts with")
{
searchEnd = "%";
}
else if (SEARCH_OPTION == "Ends with")
{
searchStart = "%";
}
else if (SEARCH_OPTION == "Contains")
{
searchStart = "%";
searchEnd = "%";
}
// Dynamically compose the SQL statement to execute.
var sqlCommand = "select c.column_name from information_schema.COLUMNS c JOIN information_schema.TABLES T ON T.table_name = c.table_name AND T.table_schema = c.table_schema WHERE T.table_schema = ''";
sqlCommand+= SCHEMA_NAME;
sqlCommand+= "'' AND T.table_name= ''";
sqlCommand+= TABLE_NAME;
sqlCommand+= "'' AND c.data_type NOT IN (''TIMESTAMP_TZ'',''BOOLEAN'',''NUMBER'') ORDER BY ordinal_position";
// Prepare statement.
var stmt = snowflake.createStatement({ sqlText: sqlCommand });
// Execute Statement
var rs = stmt.execute();
var columnArray = [];
var columnName = "";
while (rs.next())
{
columnName = rs.getColumnValue(''COLUMN_NAME'');
columnArray.push(columnName);
}
var queryPrefix = "SELECT ''dummy''"
for(var i=0; i< columnArray.length; i++)
{
queryPrefix += "," + columnArray[i];
}
queryPrefix+= " FROM " + SCHEMA_NAME + "." + TABLE_NAME;
var query = "";
for(var j=0; j< KEYWORDS.length; j++)
{
query += queryPrefix;
query += " WHERE (1=0";
for(var i=0; i< columnArray.length; i++)
{
query += " OR "+ columnArray[i] + " LIKE ''" + searchStart + KEYWORDS[j] + searchEnd + "''";
}
query += ")";
if(j < KEYWORDS.length - 1)
query += " UNION ";
}
// Prepare statement.
stmt = snowflake.createStatement({ sqlText: query });
// Execute Statement
rs = stmt.execute();
var resultArray = [];
var row_as_json = {};
while (rs.next())
{
// Put each row in a variable of type JSON.
row_as_json = {};
// For each column in the row...
for (var i=0; i< columnArray.length; i++)
{
row_as_json[columnArray[i]] = rs.getColumnValue(columnArray[i]);
}
// Add the row to the array of rows.
resultArray.push(row_as_json);
}
return resultArray;
';

A different suffix for each line on Highstock/Highcharts with Thingspeak source

I've got the code for Highcharts in combination with Thingspeak from here:
https://forum.arduino.cc/index.php?topic=213058.0
My problem is, I am not able to implement the different suffix into the code :-(. I've tried a lot, but I dont understand the mechanism behind the Java code.
I've tried some things, but result is, I only have one datafield for the first series but not for the other series...
Formatter function is on line 246.
My different yAxies on line 286.
How can formatter decide which yAxies do actual series use?
Maybe somebody have fun to help me?
http://jsfiddle.net/cbmj8rku/
Best regards, David
Each series is assigned to one yAxis. You can detect which series uses which axis for example by axis title:
tooltip: {
formatter: function() {
var points = this.points,
title,
result = '';
Highcharts.each(points, function(p) {
result += p.y;
title = p.series.yAxis.axisTitle.textStr;
if (title === 'yAxis1') {
result += 'suffix1<br>'
} else if (title === 'yAxis1') {
result += 'suffix2<br>'
} else {
result += 'suffix2<br>'
}
});
return result
}
}
Live demo: http://jsfiddle.net/BlackLabel/ncvtxoke/
I changed the code like this:
http://jsfiddle.net/cbmj8rku/20/
formatter: function() {
var d = new Date(this.x + (myOffset*60000));
var _Min = (d.getMinutes()<10) ? '0' + d.getMinutes() : d.getMinutes();
var _Sec = (d.getSeconds()<10) ? '0' + d.getSeconds() : d.getSeconds();
var s = d.getHours() + ':' + _Min + ':' + _Sec + '<br/>';
$.each(this.points, function () {
s += '<br/>' + this.series.name + ' <b>' + this.y + this.series.yAxis.userOptions.labels.suffix + '</b>';this.series.tooltipOptions.valueSuffix[this.point.index];
});
return s;
}

Open infowindow with sidebar on Google Fusion Table

For the life of me, I can't get this map to open infowindows on the sidebar link clicks: http://web.redding.com/static/redd/asphalt/prod/xmas-lights-2014-complex.html
Here's the fusion table: https://www.google.com/fusiontables/DataSource?docid=1WrvKdTypAmZozAIVeOw4vBX2g1hPInyVyuqn8GUM
Which looks like this (CSV):
Location,Description,Photo,Winner,Name
"1101 Twin View Boulevard, Redding CA",Redding's finest media organization with decades of experience & class.,http://mediaassets.redding.com/photo/2014/03/15/youthcamp17b-01_3471502_ver1.0.jpg,,The Record Searchlight
"1500 Court Street, Redding CA",Shasta Courthouse,,,
"777 Cypress Avenue, Redding CA",City Hall,,,
All I want to do is be able to click on the links in the sidebar and have the associated infowindow open on the map.
I'm new to javascript so I wouldn't be surprised if there's something obvious I'm overlooking.
Code from the linked page:
function createSidebar() {
//set the query using the parameter
var query = new google.visualization.Query(queryText);
var queryText = encodeURIComponent("SELECT 'Name','Description' FROM 1uQLxgNdNR_etBFP8O_0YNDA38PqyZB3NidIJfsgX");
var query = new google.visualization.Query('http://www.google.com/fusiontables/gvizdata?tq=' + queryText);
//set the callback function
query.send(getData);
}
function myFTclick(row) {
var Name = FTresponse.getDataTable().getValue(row,0);
var Description = FTresponse.getDataTable().getValue(row,1);
var Location = FTresponse.getDataTable().getValue(row,2);
var Photo = FTresponse.getDataTable().getValue(row,5);
var Winner = FTresponse.getDataTable().getValue(row,7);
var position = new google.maps.LatLng(lat, lng);
// Set up and create the infowindow
if (!infoWindow) infoWindow = new google.maps.InfoWindow({});
var content = '<div class="FT_infowindow">' + name;
if (Description) content += '<br>'+Description;
if (Location) content += '<br>'+Location;
if (Photo) content += '<br>'+Photo;
if (extraContent) content += "<br>["+extraContent+"]";
content += '<br>'+'zoom in';
content += '</div>';
infoWindow.setOptions({
content: content,
pixelOffset: null,
position: position
});
// Infowindow-opening event handler
infoWindow.open(map);
}
var FTresponse = null;
//define callback function, this is called when the results are returned
function getData(response) {
if (!response) {
alert('no response');
return;
}
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
FTresponse = response;
//for more information on the response object, see the documentation
//http://code.google.com/apis/visualization/documentation/reference.html#QueryResponse
numRows = response.getDataTable().getNumberOfRows();
numCols = response.getDataTable().getNumberOfColumns();
//concatenate the results into a string, you can build a table here
fusiontabledata = "<table><tr>";
fusiontabledata += "<th>" + response.getDataTable().getColumnLabel(1) + "</th>";
fusiontabledata += "</tr><tr>";
for(i = 0; i < numRows; i++) {
fusiontabledata += "<td><a href='javascript:myFTclick("+i+")'>"+response.getDataTable().getValue(i, 1) + "</a></td>";
fusiontabledata += "</tr><tr>";
}
fusiontabledata += "</table>"
//display the results on the page
document.getElementById('sidebar').innerHTML = fusiontabledata;
}
You have a javascript error in your code, look at the javascript console: Uncaught Error: Invalid column index 2. Should be an integer in the range [0-1].
Your query only includes two columns from the table:
var queryText = encodeURIComponent("SELECT 'Name','Description' FROM 1uQLxgNdNR_etBFP8O_0YNDA38PqyZB3NidIJfsgX");
Which means you can't get any columns beyond 0 and 1, so this will not work:
function myFTclick(row) {
var Name = FTresponse.getDataTable().getValue(row,0);
var Description = FTresponse.getDataTable().getValue(row,1);
var Location = FTresponse.getDataTable().getValue(row,2);
var Photo = FTresponse.getDataTable().getValue(row,5);
var Winner = FTresponse.getDataTable().getValue(row,7);
You need to include those in your query:
var queryText = encodeURIComponent("SELECT 'Name','Description','Location','Photo','Winner' FROM 1uQLxgNdNR_etBFP8O_0YNDA38PqyZB3NidIJfsgX");
Then access them in that order:
function myFTclick(row) {
var Name = FTresponse.getDataTable().getValue(row,0);
var Description = FTresponse.getDataTable().getValue(row,1);
var Location = FTresponse.getDataTable().getValue(row,2);
var Photo = FTresponse.getDataTable().getValue(row,3);
var Winner = FTresponse.getDataTable().getValue(row,4);

ExecuteSqlCommand with output parameter

I'm using Entity Framework in an ASP.NET MVC3 application and I'm trying to use the following code:
var token = "";
this.Database.ExecuteSqlCommand("exec dbo.MyUsp", new SqlParameter("token", token));
My stored proc signature is:
CREATE PROCEDURE MyUSP(#token varchar(10) OUT)
(...)
When I use this code I get an error saying that parameter "#token" was expected but not supplied.
How do I tell EF that the token parameter is for output?
I ended up using this to get it working, but I'm sure there's a more optimal way:
var p = new SqlParameter
{
ParameterName = "token",
DbType = System.Data.DbType.String,
Size = 100,
Direction = System.Data.ParameterDirection.Output
};
var resp = this.Database.SqlQuery<String>("exec dbo.usp_GetRequestToken #token", p);
return resp.First();
var outParam = new SqlParameter();
outParam.ParameterName = "OutPutParametname";
outParam.SqlDbType = SqlDbType.Bit;//DataType Of OutPut Parameter
outParam.Direction = ParameterDirection.Output;
db.Database.ExecuteSqlCommand("EXEC ProcedureName #Param1,#Param2 OUTPUT", new SqlParameter("Param1", value), outParam);
object outParamValue = Convert.ToBoolean(outParam.Value);
You need to indicate the direction in the parameter. For example, try something like this:
var p = new SqlParameter("token", token);
p.Direction = ParameterDirection.InputOutput;
this.Database.ExecuteSqlCommand("exec dbo.MyUsp", p);
I solved this issue with following SQL and Entity Framework code
SP :
ALTER PROCEDURE [dbo].[SaveSingleColumnValueFromGrid]
(
#TableName VARCHAR(200),
#ColumnName VARCHAR (200),
#CompareField VARCHAR(200),
#CompareValue VARCHAR(200),
#NewValue VARCHAR(200),
#Result INT OUTPUT
)
AS
BEGIN
DECLARE #SqlString NVARCHAR(2000),
#id INTEGER = 0;
IF #CompareValue = ''
BEGIN
SET #SqlString = 'INSERT INTO ' + #TableName + ' ( ' + #ColumnName + ' ) VALUES ( ''' + #NewValue + ''' ) ; SELECT #id = SCOPE_IDENTITY()';
EXECUTE sp_executesql #SqlString, N'#id INTEGER OUTPUT', #id OUTPUT
END
ELSE
BEGIN
SET #SqlString = 'UPDATE ' + #TableName + ' SET ' + #ColumnName + ' = ''' + #NewValue + ''' WHERE ' + #CompareField + ' = ''' + #CompareValue + '''';
EXECUTE sp_executesql #SqlString
set #id = ##ROWCOUNT
END
SELECT #Result = #id
END
Entity Framework Code :
public FieldUpdateResult SaveSingleColumnValueFromGrid(string tableName, string tableSetFieldName, string updatedValue, string tableCompareFieldName, string uniqueFieldValue)
{
var fieldUpdateResult = new FieldUpdateResult() ;
var isNewRecord = false;
if (string.IsNullOrWhiteSpace(uniqueFieldValue))
{
uniqueFieldValue = string.Empty;
isNewRecord = true;
}
using (var dbContext = new DBEntities())
{
var resultParameter = new SqlParameter("#Result", SqlDbType.Int)
{
Direction = ParameterDirection.Output
};
var recordsAffected = dbContext.Database.ExecuteSqlCommand("SaveSingleColumnValueFromGrid #TableName,#ColumnName,#CompareField,#CompareValue,#NewValue,#Result out",
new SqlParameter("#TableName", tableName),
new SqlParameter("#ColumnName", tableSetFieldName),
new SqlParameter("#CompareField", tableCompareFieldName),
new SqlParameter("#CompareValue", uniqueFieldValue),
new SqlParameter("#NewValue", updatedValue),
resultParameter);
fieldUpdateResult.Success = recordsAffected > 0;
if (isNewRecord)
{
fieldUpdateResult.NewId = (int)resultParameter.Value;
}
else
{
fieldUpdateResult.AffectedRows = (int)resultParameter.Value;
}
}
return fieldUpdateResult;
}
var db = new DBContext();
var outParam = new SqlParameter
{
ParameterName = "#Param",
DbType = System.Data.DbType.String,
Size = 20,
Direction = System.Data.ParameterDirection.Output
};
var r = db.Database.ExecuteSqlCommand("EXEC MyStoredProd #Param OUT",outParam );
Console.WriteLine(outParam.Value);
The main part i see everyone is missing, is the OUT keyword needed after #Param.
Below is what I do for Oracle using the DevArt driver. I have a package.proc called P_SID.SID_PGet that returns a single string value. The proc is:
PROCEDURE SID_PGet(io_SID OUT varchar2) is
Begin
io_SID:=GetSID; -- GetSID just goes off and gets the actual value
End;
Below is how I call it and retrieve the SID value (I'm using this with EF 4.1 code first and this method is in the DbContext):
/// <summary>
/// Get the next SID value from the database
/// </summary>
/// <returns>String in X12345 format</returns>
public string GetNextSId()
{
var parameter = new Devart.Data.Oracle.OracleParameter("io_SID", Devart.Data.Oracle.OracleDbType.VarChar, ParameterDirection.Output);
this.Database.ExecuteSqlCommand("BEGIN P_SID.SID_PGet(:io_SID); END;", parameter);
var sid = parameter.Value as string;
return sid;
}

Phonegap contact sort order on ios

Does anyone know how to sort the contact data that phonegap liberates from iOS to javascript. The order at the moment is nothing to do with alphabetical sorting. I want to sort on last name.
Here is my contact code:
function init_contacts() {
var fields = [ "name","phoneNumbers"];
navigator.service.contacts.find(fields, contactSuccess, contactError, '');
}
function contactSuccess(contacts) {
for (n = 0; n < contacts.length; n++) {
if (contacts[n].phoneNumbers) {
for (m = 0; m < contacts[n].phoneNumbers.length; m++) {
addToMyContacts(contacts[n].name.formatted, contacts[n].phoneNumbers[m].value);
console.log('Found ' + contacts[n].name.formatted + ' ' + contacts[n].phoneNumbers[m].value);
}
}
}
$("#my_contacts").listview("refresh");
};
function contactError() {
navigator.notification.alerter('contactError!');
};
You can do this sort by hand in Javascript.
var cSort = function(a, b) {
var aName = a.lastName + ' ' + a.firstName;
var bName = b.lastName + ' ' + b.firstName;
return aName < bName ? -1 : (aName == bName ? 0 : 1);
};
function contactSuccess(contacts) {
contacts = contacts.sort(cSort);
...
};
For more fun and cleaner code you may consider using lodash
contacts = _.sortBy(contacts, ['last_name', 'first_name']);
sorting in js
function sortByitemName(a, b) {
var x = a.displayName.toLowerCase();
var y = b.displayName.toLowerCase();
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}
function onSuccess(contacts) {
contacts.sort(sortByitemName);
}
I am using this method, which is far more efficient (compared to the accepted answer)
var cSort=function(a,b){
var an=a.name.formatted.toUpperCase();
var bn=b.name.formatted.toUpperCase();
return (an<bn)?-1:(an==bn)?0:1;
};
function contactSuccess(contacts) {
contacts = contacts.sort(cSort);
...
};
Contact.name.formatted is more consistent across platforms
All names starting with the same letter will be grouped together irregardless of the case. (you can also try it to see).

Resources