Filtering aerospike LLIST - php

Can anyone please show me how to filter an Aerospike LLIST bin not by the key and return all the result using PHP.
In my case the bin 'notes' is containing many rows of key, title, desc & category. I can retrieve all rows using the following code but
I need to do a filter on the category and get the results of only those within the same category. If udf is needed please assist to show me the udf code as well and how to apply the filter to get the results.
$db = new Aerospike($config, false);<br/>
$key = $db->initKey('mynamespace', 'myset', $userid);<br/>
$list = new \Aerospike\LDT\LList($db, $key, 'notes');<br/>
$status = $list->scan($results);

The LList.scan method has an optional module name, function name pair of parameters, allowing you to call a Lua function to filter each element.
There's an example PHP script provided with the client repo, which calls an example Lua module:
function keyfilters.even_filter(element)
local remainder = -1
if type(element) == "number" then
remainder = element % 2
elseif (getmetatable(element) == getmetatable(map())) and element['key'] then
remainder = element['key'] % 2
end
if remainder == 0 then
return element
else
return nil
end
end
Is invoked by
$rental_history->scan($elements, 'keyfilters', 'even_filter');

Manage to modify the UDF as follows and it works.
local category_filters = {}
function category_filters.filterBy(element,val)
if element['category'] == val[1] then
return element
else
return nil
end
end
return category_filters
Invoked by
$status = $list->scan($results, 'category_filters', 'filterBy', array($category));

Related

How to get Position of Comment within a Post

So I have a Post which has Comments -- I'm trying to get the Comment # position within that post. For example, a Post has 15 comments, I want to be able to get the numerical position (i.e 1 (first post), 2 (second post), 3 (third post), etc, etc), and put this into a function somehow. That way when I can call $comment->position() and it will show as the 4th, 5th, whatever position in it is in.
I've done some searching around the web and couldn't find a solution. Any help is greatly appreciated! This is what I have so far:
public function position($id,$arr)
{
$total = $this->post->comments->count();
$position = $this->pluck('post_id')->search($this->id) + 1;
return ceil($total / $position);
//$comments_per_page = 25;
//$pos = array_search($id,$arr);
//$pos = $pos+1;
//return ceil($pos/$comments_per_page);
}
You should first get all your comments as collection.
// all comments as collection
$comments = $this->post->comments;
Then you can search through the collection using the search function and inserting an id you want to search for ... or any other param you want.
$id = 2;
$commentIndex = $comments->search(function($comment) use ($id) {
return $comment->id === $id;
});

Add sequential number in database, that resets every year

I am building a project using Codeigniter + MySQL + Active Record.
In my MySQL db i have a table named Requests with columns protocol,year and some other columns where i store general information of a request (like title, subject etc...), nothing special to mention.
Protocol and year are TYPE INT and must be auto generated like below.
Every year, at 01/01/XXXX-00:00:00 the protocol field must reset to number 1 (the first request saved after 01/01/XXXX, must have protocol value 1) and for the upcoming requests, increase it sequentially by 1, until next year and so on.
To reset the protocol, i will add a cron in a later phase where i will do a trick to reset. Still don't know how.
What i need to do now:
Whenever i add a new request, the protocol of the new row must be increased by 1.
Pseudocode:
new_protocol = previous_protocol + 1
What i am doing so far
I have a function in my model which Inserts a new request, but so far i do nothing about the protocol number, i enter it manually through my form.
public function addRequest($request) {
$this->db->insert('requests', $request);
if ($this->db->affected_rows() == 1)
return $this->db->insert_id();
return FALSE;
}
What is the most efficient way to achieve this?
Should i find the last protocol number in my Controller -> add 1 -> send to model to add?
Should i find the LAST and MAX protocol number in model -> add 1 -> insert to db?
Something else?
Any ideas will be appreciated.
I'd approach like so:
add column ID in your table and set it to auto-increment
php - set the default timezone to use (since PHP 5.1): date_default_timezone_set('UTC');
php - get current year: $cyear=date("Y");
get row max(ID) and compare if the stored year has changed compared to $cyear
if it has changed and following your pseudocode example:
new_protocol = 1
otherwise
new_protocol = previous_protocol + 1
Ok so i created a library in Codeigniter and wrote 2 functions, 1 in Library and 1 in Model.
Library
public function getProtocolNumber() {
$CI = &get_instance();
$year = date('Y');
$max_protocol = $CI->request_model->getYearsProtocol($year);
$max_protocol = $max_protocol['max_protocol_number'];
if ($max_protocol && !empty($max_protocol) && $max_protocol != NULL) {
$protocol_number = (int) $max_protocol + 1;
} else {
$protocol_number = 1;
}
return $protocol_number;
}
Model
public function getYearsProtocol($year) {
$qry = $this->db->select('MAX(protocol_number) as max_protocol_number')
->from('requests')
->where('protocol_year', $year)
->get();
if ($qry->num_rows() > 0)
return $qry->row_array();
return FALSE;
}

Check large chunk of values for uniqueness in database

I need to create promo codes which should be short in length (~ 6 characters). The promo codes have to be unique, so I need to check their uniqueness in database as well. They need to be generated in batches of thousands, so a check in db with every coupon generation is not feasible. I have created a method which first generates the required number of coupons and then check for duplicates using where in(). Having duplicate count of greater than zero, makes it generate the count again.
public function generateCoupons($count, $length = 6)
{
$coupons = [];
while(count($coupons) < $count) {
do {
$coupon = strtoupper(str_random($length));
} while (in_array($coupon, $coupons));
$coupons[] = $coupon;
}
$existing = Offer::whereIn('coupon', $coupons)->count();
if ($existing > 0)
$coupons += $this->generateCoupons($existing, $length);
return (count($coupons) == 1) ? $coupons[0] : $coupons;
}
Need suggestions how to improve upon this? Or if I can have some other way to achieve the same.
Make sure the promo code is indexed in your DB. This will speed up the search for existing promo codes.
Otherwise, your method is good! you want to check as many codes as possible at once (which you do with the whereIn/count) and only re-generate the codes that were not unique.
Build a table new_codes with 1000 candidates. PRIMARY KEY(code).
DELETE new_codes
FROM new_codes
LEFT JOIN existing_codes ON existing_codes.code = new_codes.code
WHERE existing_codes.code IS NOT NULL;
That (if I did it right) will very quickly delete the dups. Now you will have not-quite-1000 'good' codes.

Laravel Eloquent: how to filter multiple and/or criteria single table

I am making a real estate related app and I've been having a hard time figuring out how to set up the query so that it would return "Only Apartments or Duplexes within selected areas" I'd like to user to be able to find multiple types of property in multiple selected quadrants of the city.
I have a database with a column "type" which is either "Apartment", "House", "Duplex", "Mobile"
In another column I have quadrant_main with values: "NW", "SW", "NE", "SE".
My code works when there is only 1 quadrant selected, but when I select multiple quadrants, I seem to get results which includes ALL the property types from the second or third or 4th quadrant, instead of only "Apartment" and "Duplex" or whatever types the user selects... Any help will be appreciated! thx in advance.
My controller function looks like this:
public function quadrants()
{
$input = \Request::all();
$currentPage = null;
$column = "price";
$order = "desc";
//
// Looks like the input is like 0 => { key: value } ...
// (an Array of key/value pairs)
$q = Listing::where('status','=','Active')->where(function($query) {
$input = \Request::all();
$currentPage = null;
$typeCount = 0;
$quadrantCount = 0;
foreach( $input as $index => $object ) {
$tempObj = json_decode($object);
$key = key((array)$tempObj);
$val = current((array)$tempObj);
if ( $key == "type" ) {
if ( $typeCount > 0 ) {
$query->orWhere('type', '=', $val );
}
else {
$query->where('type', '=', $val );
$typeCount++;
}
}
if ( $key == "quadrant_main" ) {
if ( $quadrantCount > 0 ) {
$query->orWhere('quadrant_main', '=', $val );
}
else {
$query->where('quadrant_main', '=', $val );
$quadrantCount++;
}
}
// else {
// $query->orWhere($key,$val);
// }
}
if( $currentPage ) {
//Force Current Page to Page of Val
Paginator::currentPageResolver(function() use ($currentPage) {
return $currentPage;
});
}
});
$listings = $q->paginate(10);
return $listings;
Looking at your question, its a bit confusing and not much is given to answer definitely. Probable causes of your troubles may be bad data in database, or maybe corrupted input by user.
Disclaimer: Please note that chances are my answer will not work for you at all.
In that case please provide more information and we will work things
out.
There is one thing that I think you have overlooked and thus you are getting awry results. First let me assume a few things.
I think a sample user input should look like this:
array(
0: '{type: Apartment}',
1: '{type: Duplex}',
2: '{quadrant_main: NW}',
3: '{quadrant_main: SW}',
)
What the user meant was give me any apartment or duplex which belongs in NW or SW region.
So after your loop is over, the final SQL statement should be something like this:
Oh and while we are at SQL topic, you can also log the actual
generated SQL query in laravel so you can actually see what was the
final SQL getting generated. If you can post it here, it would help a
lot. Look here.
select * from listings where status = 'Active' and (type = 'Apartment' or type = 'Duplex' and quadrant_main = 'NW' or quadrant_main = 'SW');
What this query will actually produce is this:
Select any listing which is active and:
1. Type is an apartment, or,
2. Type is a duplex, or,
3. Quadrant is SW, and,
4. Quadrant is NW
So assuming you have a database like this:
id|type|quadrant_main
=====================
1|Apartment|NW
2|Apartment|SW
3|Apartment|NE
4|Apartment|SE
5|Duplex|NW
6|Duplex|SW
7|Duplex|NE
8|Duplex|SE
9|House|NW
10|House|SW
11|House|NE
12|House|SE
You will only receive 1, and 5 in the result set. This result set is obviously wrong, plus it is depended on NW because that was the and condition.
The correct SQL query would be:
select * from listings where status = 'Active' and (type = 'Apartment' or type = 'Duplex') and (quadrant_main = 'NW' or quadrant_main = 'SW');
So structure your L5 app such that it produces this kind of SQL query. Instead of trying to cram everything in one loop, have two loops. One loop should only handle type and another loop should only handle quadrant_main. This way you will have the necessary and condition in the right places.
As a side note:
Never directly use user input. Always sanitize it first.
Its not a best practice to put all your logic in the controller. Use repository pattern. See here.
Multiple where clauses are generally applied via Criteria. Check that out in the above linked repository pattern.
You code logic is very complicated and utterly un-necessary. Instead of sending JSON objects, simply send the state of checkboxes. Don't try to generalize the function by going in loop. Instead handle all checkboxes one by one i.e. is "Apartments" selected, if yes, add that to your clause, if not, don't add.

ZendSearch Lucene boolean query doesn't correct work with numbers

I'm new with Zend Framework 2 and ZendSearch Lucene.
My database table has three columns with integers, the first one is for the id.
In the second is the publish value (1 to 3), in the third is the category value (1 to 5).
The Table looks like this:
|id|publish|category|
|1|1|1|
|2|1|2|
|3|1|3|
|4|2|3|
|5|2|4|
I tested this with the following queries:
"publish:1" Return the correct id's 1,2,3;
"publish:2" Return the correct id's 4,5;
"publish:3" Return the incorrect id's 1,2,3,4,5; The result should be empty.
"publish:1 AND category:1" Return the correct id 1;
"publish:1 AND category:3" Return the correct id 3;
"publish:1 AND category:4" Return the correct empty result;
"publish:1 AND category:5" Return the incorrect id's 1,2,3; The result should be empty.
When a number doesn't exist, the result is not empty, it contains all rows.
Is there any option, that the result is empty when the number doesn't exist?
The default encoding is UTF-8:
\ZendSearch\Lucene\Search\QueryParser::setDefaultEncoding('UTF-8');
\ZendSearch\Lucene\Analysis\Analyzer\Analyzer::setDefault(new \ZendSearch\Lucene\Analysis\Analyzer\Common\Utf8Num\CaseInsensitive());
The id is unindexed, publish and category are keywords.
I think I found the answer.
When I build the query with the following code the query is "+(publish:1) +(category:1)" and this works.
$query = new \ZendSearch\Lucene\Search\Query\Boolean();
$termPublish = new \ZendSearch\Lucene\Index\Term(1, 'publish' );
$subqueryPublish = new \ZendSearch\Lucene\Search\Query\Term($termPublish);
$query->addSubquery($subqueryPublish, true); // required
$termCategory = new \ZendSearch\Lucene\Index\Term(1, 'category' );
$subqueryCategory = new \ZendSearch\Lucene\Search\Query\Term($termCategory);
$query->addSubquery($subqueryCategory, true); // required

Categories