Here is my code. But I have some problem about loading time for result more than 1000 rows.
How can I change code to check number of query result for create paginate first. Then, get result only that paginate page?
function showResult(req, res){
var n = req.query.query;
mysql_conn.query('SELECT query_text FROM catalogsearch_query WHERE query_text LIKE "%' + n + '%" ORDER BY popularity DESC LIMIT 0 , 10', function (error, rows) {
mysql_crawl.query('SELECT prod_name, full_price, discount_price, quantity, fulltext_id,prod_link, images, prod_desc, status, web_name,web_logo FROM `catalogsearch_fulltext` WHERE MATCH(data_index) AGAINST("'+n+'") ', function(error, product_data) {
var totalItems = product_data.length, itemts=product_data;
//set default variables
var totalResult = totalItems,
pageSize = 10,
pageCount = Math.floor(totalResult / pageSize)
currentPage = 1
//set current page if specifed as get variable (eg: /?page=2)
if (typeof req.query.page !== 'undefined') {
currentPage = +req.query.page;
}
//render index.ejs view file
res.render('result.html', {result: n,
related: rows.map(row => row.query_text),
page_num: p,
product_data: product_data,
totalItems: totalItems,
pageSize: pageSize,
pageCount: pageCount,
currentPage: currentPage})
});
});
}
first you get the total rows of the result
SELECT COUNT(*) FROM table WHERE 1 = 1;
second is the query to get the rows result but limit by ex. 10 and offset starts at zero first
SELECT * FROM table WHERE 1 = 1 LIMIT 10, 0;
it means the result will start at 0 then for the next page you should add 10 for your offset
SELECT * FROM table WHERE 1 = 1 LIMIT 10, 10;
so it starts at 10 up to 20
So actually two sides: client side and server side.
Client side, using angularjs, please evaluate to use the angular ui pagination directive:
https://github.com/angular-ui/bootstrap/tree/master/src/pagination
Here a link to a stackoverflow post where there is a working example of it:
How to do paging in AngularJS?
About your server side, you could provide a way to make your query dynamic, retrieving just results in the range you pass on it. So something like that:
'SELECT query_text FROM catalogsearch_query WHERE query_text LIKE "%' + n + '%" ORDER BY popularity DESC LIMIT %, %'
where you pass your limit parameters from the client according to the pagination.
So before to load a new page, you call the query with the right LIMIT parameters
Related
I am creating a fixed asset depreciation calculator with VueJS. The issue is calculating double declining balance and listing results in a table showing year, depreciated amount in each year a long the useful years of the asset and the book value in each year. I want something like this:
Purchase price = 25000
useful years = 5
**
Year| Depreciated Amount| Book Value
1 | 9000 |16000
2 | 6000 |10000
**
Asset purchase price and useful years is dynamically supplied by the user. Like in my example above, the loop should run 5 times (5 useful years).
This my code:
reducingBalDepCal()
{
//Calculates asset depreciation based on declining balance
//hide previous results if any
this.showResults = false;
//This is the historical cost of the fixed asset. The value is being supplied by the user.
var purchasePrice = this.reducingbal.purchase_price;
//The number of years the asset will be useful to the business. Its the lifespan of the asset in the operational business. The vulue is being supplied by the user.
var usefulYears = this.reducingbal.useful_years;
//is calculated by dividing 100% with asset useful years.
var rate = (100/usefulYears);
//Then the rate is doubled
var doubleDepreciationRate = rate*2;
var depAmount = []; //This array holds depraciated amount each year. i.e current book value-current depreciated amount
var writenDownValue = []; //This array holds the current book value in each depreciation iteration
//The for loop calaculates the depreciation in each year depending on the number of useful years and stores current depreciated amount in the depAmount array and the current writen down amount (book value) in the writenDownValue array.
for(var i=usefulYears+1;i>1;i-=1)
{
writenDownValue.push(purchasePrice-=(doubleDepreciationRate/100)*purchasePrice);
depAmount.push(purchasePrice-writenDownValue[i]);
}
//Assigns the results on data variable
//this.reducingBalProjection =depAmount;
this.showReducingBalProjection = true;
console.log(writenDownValue);
console.log(depAmount);
},
This is the result for depAmount array:
(50) [15000, 9000, 5400, 3240, 1944, 1166.4, 699.84, 419.904, 251.9424, 151.16544, 90.699264, 54.4195584, 32.65173504, 19.591041024, 11.754624614399999, 7.052774768639999, 4.231664861183999, 2.5389989167103995, 1.5233993500262397, 0.9140396100157437, 0.5484237660094462, 0.3290542596056677, 0.1974325557634006, 0.11845953345804036, 0.07107572007482421, 0.04264543204489453, 0.025587259226936717, 0.01535235553616203, 0.009211413321697217, 0.00552684799301833, 0.003316108795810998, 0.0019896652774865986, 0.0011937991664919593, 0.0007162794998951756, 0.00042976769993710535, 0.0002578606199622632, 0.00015471637197735793, 0.00009282982318641476, 0.00005569789391184885, 0.00003341873634710931, 0.000020051241808265585, 0.00001203074508495935, 0.0000072184470509756104, 0.000004331068230585366, 0.0000025986409383512197, 0.0000015591845630107317, 9.35510737806439e-7, 5.613064426838634e-7, 3.36783865610318e-7, 2.020703193661908e-7]
And result for writenDown array:
[ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -0.017058172817957813, -0.05572336453866218, -0.10924812013634315, -0.19190570777038227, -0.3257381508098567, -0.5464341007319596, -0.9128458108492518, -1.5226830705263446, -2.5385691490104625, -4.231407000564037, -7.052620052268022, -11.754531784576812, -19.590985326106086, -32.65170162126365, -54.41953834875819, -90.69925196925492, -151.16543278155294, -251.94239566893177, -419.90399740135905, -699.8399984408155, -1166.3999990644893, -1943.9999994386935, -3239.999999663216, -5399.999999797929 ]
Both results are semantically wrong. I expect the loop to run usefulyears fold. But both loops are not doing what I expected and probably doing what I told it do. I cant figure out how exactly can achieve the intended results.
Another worry how can I package the do arrays and print them out in a table like this:
Year| Depreciated Amount| Book Value
1 | 9000 |16000
2 | 6000 |10000
Please Help.
If you're getting two arrays of length 50, isn't the main issue that this.reducingbal.useful_years is incorrectly set?
Anyway, implementing the calculation as described here gives me different results than your first two years of 9000 and 6000:
(function() {
// A table row
const Row = (nr, start, apdr) => ({
year: nr,
startValue: start,
depExpense: start * apdr,
endValue: start - (start * apdr)
})
// The calculation
const decliningBalanceDepreciation = multiplier => (
startValue,
endValue,
years
) => {
const valueDecrease = startValue - endValue;
// Applicable Percentage Depreciation Rate
const apdr = (valueDecrease / years) / valueDecrease * multiplier;
const rows = [
Row(1, startValue, apdr)
];
for (let i = 1; i < years; i += 1) {
rows.push(
Row(i + 1, last(rows).endValue, apdr)
)
}
return rows;
};
const dblDecBalDep = decliningBalanceDepreciation(2);
console.log(
dblDecBalDep(25000, 0, 5)
);
function last(arr) { return arr[arr.length - 1]; }
}())
I'm using vuejs for this project, but this problem is not necessarily connected - but if there is a vue-way, I would prefer that.
I'm building a table, that enables the user to have per-column-filters (in this case simple inputs). The columns are dynamic, so is the amount of data (thousands of rows, but less than 100.000 entries).
// example data
var columns = ['id', 'title', 'date', 'colour']
var data = [{ id: 1, title: 'Testentry 1', date: '2017-02-21T07:10:55.124Z', colour: 'green'}]
Here is the problem: I'm iterating over the columns, checking if a search-input exists, and if so, I try to filter the data based on the searchquery. In case of the ID, the time complexity is O(n). If I know search for a title additionally, I can reuse the result of the first searchquery, dramatically reducing the amount of data has to be looked at.
The searchqueries are stored in an object search, and the filtered data is a computed property, that gets updated whenever search changes. The way how that works though is, that if I change the searchquery for title, it would re-evaluate the searchquery even for the ID, although the searchquery for that didn't change.
This would require some kind of caching of data filtered for each column. And only the proceeding columns need to be queried upon.
edit: added code for the filtering:
filteredRows () {
var rows = this.data
for (var i = 0; i < this.columns.length; i++) {
var column = this.columns[i].name
var search = this.tSearch[column]
if (!search && search.length === 0) continue
console.log(column + ': ' + ' (' + search + ') -> ' + rows.length)
rows = _.filter(rows, (row) => {
var value = '' + row[column]
value.search(search) > -1
})
}
return rows
}
Just a suggestion, but did you try to use a watcher to get old and new value of input.
data: function() {
return {
propertyToWatch: 'something'
}
},
computed: {
...
},
watch: {
'propertyToWatch': function (val, oldVal) {
console.log(oldVal); // logs old value
console.log(val); // logs current value
// here you can call a function and send both of these args and detect diff
}
},
....
I found this method, with which I have ordered the hours what I store in my records, I wanted them to be sorted from highest to lowest, but when I test the code, I notice that only two values of the array are compared, which are the first registers.
I've seen other methods of comparison and the logic is the same, what am I doing wrong? I group the messages per user, using the id of the user as key of the array , then I save the rest of data. I do this for retrieve the current messages, since I want show a list of the last currently messages sent.
This is the code:
var ref = new Firebase('https://chatfbexample.firebaseio.com/all-messages');
ref.on("value", function (snapshot) {
var Messages = [];
var value = 0;
snapshot.forEach(function (snap) {
value = snap.val().id;
fecha = snap.val().id;
Messages[value] = [];
Messages[value]['fecha'] = snap.val().fechahora; //I receive a date with the format HH:MM:SS
Messages[value]['texto'] = snap.val().texto;
});
function compare(a, b) {
var time1 = a['fecha'].replace(/:/gi, '1');
var time2 = b['fecha'].replace(/:/gi, '1');
var data1 = parseInt(time1);
var data2 = parseInt(time2);
// alert(time1);
if (data1 > data2)
return -1;
if (data1 < data2)
return 1;
return 0;
}
Messages.sort(compare);
for (var i in Messages) {
console.log("Hour: " + Messages[i]['fecha'] + ' ' + ' Message: ' + Messages[i]['texto']);
}
});
the result is something like this
Hour: 12:11:13 Message: whats'up?
Hour: 11:38:44 Message: p
Hour: 11:49:01 Message: hey?
the second and the third messages are not being compared
an image of my Firebase database
First off it probably would be better for you to save a timestamp from Firebase instead of an actual time, which was probably created on the client side, inside your database. This way you could easily let Firebase handle the sorting.
You would need to use firebase.database.ServerValue.TIMESTAMP to save the exact time at which Firebase received your message inside fechahora.
Following you could simply query all of your messages ordered by their child fechahora.
ref.orderByChild("fechahora").on("value", function (snapshot) {
//Do stuff with your already sorted data
}
If you want your query to have a better performance set the .indexOn property of your node containing all the messages inside your Firebase Database rules to fechahora.
Bonus: If you want your data to be ordered newest to oldest instead of oldest to newest, you just need to use the negative value of the timestamp created by Firebase.
Instead of ordering client-side, you'll be better off asking the server to sort the messages:
ref.orderByChild("fechahora").on(...
Make sure that you define the proper index in your Firebase security rules:
{
"rules": {
"all-messages": {
".indexOn": "fechahora"
}
}
}
Without that the sorting will still work, but will happen on the client instead of the server.
If I have the following queryBuilder query in the node.js client API:
db.client.documents.query(
q.where(
q.collection('records'),
q.or(
q.value('id', [1,2,3,4])
)
).slice(0, 50)
)
This would give me the first 50 records related to this query. It would also give me a count of 50, even if there are 1000 records related to this query.
If I do a query with:
.withOptions({categories: 'none'})
I can see the real count for the query.
Is there a built-in option to give me a single page of data AND get the full count for the query?
In order to support paging, you would have to first call .withOptions({categories: 'none'}) to get the total count of records and then .withOptions({categories: 'content'}) to get the actual content. Following is very nice article on paging:
http://www.tamas.io/marklogic-and-node-js/
As per my knowledge there is no built-in way to fetch both total count and data together.
This will do what you're looking for:
db.documents.query(
qb.where(
qb.term('apple')
)
.slice(1, 10)
.withOptions({categories: 'content', metrics: true})
).result()
.then(function(docs) {
console.log('I have ' + docs.length + ' docs');
})
.catch(function(error) {
console.log('something went wrong');
});
In the then function, docs will be an array of length 11. The first item in the array will be the metrics:
{
"metrics": {
"query-resolution-time": "PT0.00179S",
"snippet-resolution-time": "PT0.00505S",
"total-time": "PT0.008708S"
},
"page-length": 10,
"results": [],
"snippet-format": "snippet",
"start": 1,
"total": 20
}
The results array will have the snippets. Items 1 through 10 of the array will have the full contents of the document.
I'm having a problem with my JSON array. On first load, the order is not as it should be (as defined in the SQL query).
So the main problem is, on page load, i.e. when the SQL query is called with lastPoll=null - the results are not sorted by time1 DESC, yet they are sorted by the s.id ASC. When I enter a new result, and then run the query with the lastPoll set in the query, then the latest is added to the top, as it should be.
Weird part is - if I view the raw JSON response at push.php with the correct params in the URL, the response is correct and in the correct order. So, the problem must lie in the parsing?
Here is the SQL Query:
$getActivityUpdates1 = mysql_query("
SELECT
s.id, u.name, u.profilePic, s.userid, s.content, s.time1, s.imageKey
FROM
status_updates s
INNER JOIN
users1 u ON u.id = s.userid
WHERE
competitionId = '$competitionId' AND s.time1 > '$lastPoll'
ORDER BY s.time1 DESC");
$results = array('items' => array());
while ($row = mysql_fetch_array($getActivityUpdates1))
{
$results['items'][] = array(
'statusid' => $row['id'],
'name' => $row['name'],
'profilePic' => $row['profilePic'],
'content' => $row['content'],
'time1' => $row['time1'],
'imageKey' => $row['imageKey'],
);
}
die(json_encode($results));
?>
Here is the Javascript where I re-run the query.
var lastPoll = null;
function loadActivity(onDone) {
var competitionId = $("body").attr("data-competitionId");
console.log(lastPoll);
if (lastPoll == null) { // We have never polled, we want to pull everything and populate the list.
url = "push.php?competitionId=" + competitionId + "&lastPoll=1999-01-01 22:00:00";
} else { // We have polled once, send the date and time of that last poll to capture only new entries.
url = "push.php?competitionId=" + competitionId + "&lastPoll=" + lastPoll;
}
$.get(url, function(data) {
jsonData = $.parseJSON(data);
var spot = $("#activityspot");
var template = spot.find(".template");
for (var j = 0; j < jsonData.items.length; j++) {
var entryData = jsonData.items[j];
var entry = template.clone();
entry.removeClass("template");
entry.find(".message").text(entryData.statusid);
spot.prepend(entry);
}
if (onDone) {
onDone();
}
lastPoll = js_yyyy_mm_dd_hh_mm_ss();
});
}
You are producing your results in reverse time order, but then also adding them to the page in reverse order (with .prepend). The net result is that the two reversals cancel each other out such that each batch of results is added to the top of the list in ascending time order.
If the intent is to actually have them displayed in reverse order just get rid of the DESC qualifier from the query and rely on the .prepend call to add each successive entry to the top of the page.