Checking 2 Column for Duplicate - mysql

Currently, I have a system to hold main data
1) The email
2) The owner(user_id)
Every time someone uploads , I need to make sure that it doesn't not exist in the system. The catch is as I upload more and more, the amount of time taken to check for duplicate will grow steeply, just like the graph as shown.
Question
1) How do i check for duplicate efficiently?
2) I indexed the user_id and the email should I Fulltext it? I wont be reading the text but will be searching for it as a whole, so index is more logical?
3) I also read about creating Hash combining email&owner id then index the hash. Will it be a big difference from the current method?
4) Last method i thought of was to create a primary key for both email and user_id , once again idk how the performance would turn out.
Please advice.
Code
$exist = DB::table('contact')->where('email', $row['email'])->where('user_id', $user_id)->count();
if($exist < 1){
DB::table('contact')->insert(
['email' => $row['email'], 'name' => $row['name'], 'user_id' => $user_id]
);
}

Use Laravel Validator:
public function store(Request $request)
{
$this->validate($request, [
'user_id' => 'required|unique',
'email' => 'required|unique',
]);
//some logic here
}
Also you should use unique constraint in your database.

Related

Failed DB update requests with Laravel

After spending numerous hours on this and scouring the answers online, I'm royally stuck on a seemingly simple DB update with Laravel. Here is a (simplified) version of the flawed function in one of my controllers:
public function changeDetails(Request $request)
{
...
// It works to change member_id into another...
if (Request::input('recipient_id') != "null") {
DB::table('recipients')
->where('recipients.id','=',Request::input('recipient_id'))
->update([
'recipients.member_id' => Request::input('member_id')
]);
// ...but it won't let me change it to NULL.
} else {
DB::table('recipients')
->where('recipients.id','=',Request::input('recipient_id'))
->update([
'recipients.member_id' => null
]);
};
I initially thought that the issue had to do with the database or table, especially since the 'member_id' is a foreign key. However, I did two tests that prove otherwise. First, I made sure that the column is 'unsigned' and 'nullable'. Second, I manually inserted an integer into the "where" clause instead of the "Request::input('recipient_id')"... and it worked fine. I also confirmed that the value of "Request::input('recipient_id')" is indeed an integer, which should work within the appropriate column (that is 'bigint' type).
Any useful suggestions/observations? They would be greatly appreciated.
The code runs into else statement only when Request::input('recipient_id') is "null",
but your else statement also uses 'recipient_id' which is "null".
So your SQL statement will find a recipients where recipients.id = "null".
Obviously you don't have any "recipient_id" is "null", right?
...
else {
DB::table('recipients')
->where('recipients.id','=',Request::input('recipient_id')) // here the recipient_id is "null"
->update([
'recipients.member_id' => null
]);
};
...

YII2 Session saving multiple record on one request

i'm trying to use Dbsession to track user' activity and i got everything set and running according to yii documentation, but when a user load a page multiple session record was saved in the database in one request. image below shows the data in the database what is the cause of this and any solution to fix this?
In my config file i have this
'session' => [
// this is the name of the session cookie used for login on the frontend
//'name' => 'advanced-frontend',
'class' => 'yii\web\DbSession',
'writeCallback' => function ($session) {
return [
'user_id' => \Yii::$app->user->id,
'ip' => \Yii::$app->clientip->get_ip_address(),
];
},
],
First column (id) is primary key and should be unique (it is declared in this way in migration). You have probably messed something with table schema - you should not be able to save 3 records with the same ID. DbSession is using upsert() and relies on uniqueness of id column.
Make sure that id column is primary key, or at least have UNIQUE constraint.

Laravel updateOrCreate with auto-incremental database

My purpose is to update if the value exists, else inserts a new row in the database table after submitting the form.
The problem is, the function here adds new columns in db table instead of updating them.
Here's my function :
MyModel::updateOrCreate(array(
'myField' => 'myValue',
))
->where('myAutoIncrementalField', '=', '5')
->where('myPrimaryKey', '=', '8');
My database table is like that :
1. myPrimaryKey (not auto incremental and is fillable on model.)
2. myAutoIncrementalField (auto incremental and cannot be fillable on model.)
Thank you in advance.
This is how you use this method:
Model::updateOrCreate(
['primary_key' => 8],
['field' => 'value', 'another_field' => 'another value']
);
As 1st param pass an array of fields that are unique, or in your case, the primary key. Non-unique fields don't make sense here obviously just like passing anything along with the PK.
2nd param is an array of values that should be updated/created too, but being ignored in the unique/pk search.
You cannot use where functions with this method. You have to include the where clauses in the array.
MyModel::updateOrCreate(array(
'myField' => 'myValue',
'myAutoIncrementalField' => '5',
'myPrimaryKey' => '8'
));

WordPress Custom Select Query

I really don't know enough about MySQL queries and it's showing.
I have a custom field set for every post. The custom field stores the posts source URL in a key called "source_url".
I have it working with the below WP_Query parameters, but it's incredibly slow. Keep in mind it's possible to 50+ urls to search for.
So, given an array of source URL's, I want to fetch the matching posts.
For example, here is what I currently have that's slow in WP_Query:
// var_dump of $urls array (this could be 50+ urls)
array(7) {
[0]=>
string(42) "http://www.youtube.com/watch?v=FMghvnqDhT8"
[1]=>
string(42) "http://www.youtube.com/watch?v=RY-yUFpXTnM"
[2]=>
string(58) "http://www.youtube.com/watch?v=nIm2dnyJ1Ps&feature=related"
[3]=>
string(42) "http://www.youtube.com/watch?v=NoCtRQlJAqM"
[4]=>
string(57) "http://holidaycustoms.blogspot.com/2012/08/busy-week.html"
[5]=>
string(42) "http://www.youtube.com/watch?v=DcZvg197Ie4"
[6]=>
string(42) "http://www.youtube.com/watch?v=7P3UEbLmLuo"
}
// Build Media Query
$meta_query = array(
'relation' => 'OR'
);
foreach( $urls as $url ) {
$meta_query[] = array(
'key' => 'source_url',
'value' => $url
);
}
// Get 20 matching posts from a category set by a variable
$args = array(
'post_type' => 'post',
'posts_per_page' => 20,
'orderby' => 'rand',
'cat' => $cat_ID,
'meta_query' => $meta_query
);
$posts = get_posts($args);
What I'm looking to do is replace the above code with a custom query select, which I have read is much faster than WP_Query.
But I don't know enough about MySQL or the WP database to build the custom select query. Can anyone help? Thanks in advance!
In the post you linked yourself, the first reply already states that
[...] the default schema doesn't even have an index on the value column
Which is far more severe a problem than any you would have with a query generator, because without an index the DBMS has to traverse the whole table and compare strings of each field.
Adding an index is fairly easy with an appropriate management tool like PHPMyAdmin. The offending table you will need to add an index to is called wp_postmeta and the field that needs an index is meta_value, and the index type should be INDEX.
Adding an index is transparent and does not affect wordpress other than in performance. It could take some time though since, well MySQL needs to traverse the whole table. Also, because you are indexing string data, the index will be quite big.
You should also try using appropriate structures for your query. You are currently using a big ORed selection with different values but always the same field. There is a construct for just that, and it's called IN.
...
// Build Media Query
$meta_query = array();
$meta_query[] = array(
'key' => 'source_url',
'value' => $urls,
'compare' => 'IN'
);
// Get 20 matching posts from a category set by a variable
..
(Untested. I actually never did this, Reference)
The performance gain would be negligible compared to adding an index I assume, but your code would become a lot simpler.

UPDATED: Magento add customer attribute filter to order grid

I have extended the Mage_Adminhtml_Block_Sales_Order_Grid class with a custom module to add several customer attributes (Magento EE 1.10) to the grid.
Two of the attributes I added are text fields (i.e. they live in the customer_entity_varchar table, and I was able to add them to the collection and display them in the grid. So far so good.
A third attribute is a select, so the values live in the customer_entity_int, the eav_attribute_option and the eav_attribute_option_value tables. I added the necessary values to the collection (using $collection->getSelect()->joinLeft(.....). Again, so far so good.
My problem is being able to display and filter the attribute at the same time.
Inside the _prepareColumns() function in my MyCompany_MyModule_Block_Adminhtml_Order_Grid class, if I add a column like this, - as expected - I can display the values of the attribute on each row, but I don't get a drop down filter in the header:
protected function _prepareColumns()
{
...
$this->addColumn('bureau', array(
'header' => Mage::helper('sales')->__('Bureau'),
'index' => 'bureau',
'type' => 'text'
));
...
}
Following the example of status, and adding the column like this, gives me the drop down filter in the header, but it no longer displays the values for the attribute in each row:
protected function _prepareColumns()
{
...
$this->addColumn('bureau', array(
'header' => Mage::helper('sales')->__('Bureau'),
'index' => 'bureau',
'type' => 'options',
'options' => $this->_getBureauOptions(),
'filter_index' => 'value_option_table.option_id'
));
...
}
protected function _getBureauOptions()
{
$bureau = Mage::getResourceModel('eav/entity_attribute_collection')
->setCodeFilter('bureau')
->getFirstItem();
$bureauOptions = $bureau->getSource()->getAllOptions(false);
$optionsArr = array();
foreach ($bureauOptions as $option) {
$optionsArr[$option['value']] = $option['label'];
}
return $optionsArr;
}
Any advice / explanation would be much appreciated.
UPDATE:
It turns out that my code also causes a SQL error in a multi-website environment when an admin user only has permissions for some websites:
"SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'store_id' in where clause is ambiguous"
#clockworkgeek had the answer to the first part of my question.
The problem was that my joinLeft() was retrieving text values from the attribute options, while I should have been retrieving integer values when using 'type => 'options'.
Once I changed my joinLeft() to only retrieve integer values from customer_entity_int (actually a simpler join), the filtering and display worked flawlessly - thank you sir.
I will re-post my second issue (about SQL errors caused by permissions) as a separate question.