Should I use Query Builder for this in Laravel 9?
DB::table('galleries')->insert(
['book_id' => $book->id, 'photo' => $name, 'cover' => 1],
);
or Laravel Eloquent?
Gallery::create(
['book_id' => $book->id, 'photo' => $name, 'cover' => 1],
);
And what is the difference?
They are both basically the same. The only difference comes when you want to insert a huge amount of data.
The performance of query builder is much faster than that of the eloquent ORM when handling VERY LARGE amounts of data.
insert() Query builder method difference:
the difference is, Query Builder insert() runs mysql raw insert query under the hood and As like mysql raw query you can create multiple rows in single query.
DB::table('galleries')->insert(
['book_id' => $book->id, 'photo' => <photo A path>, 'cover' => 1],
['book_id' => $book->id, 'photo' => <photo B path>, 'cover' => 0],
);
The above query will insert two rows in single query.
The second thing is, It is very fast and optimize in speed as compare to eloquent builder create() method.
Third, It's not emits model events i.e. creating, created events etc.
It's not returns created models in result.
create() eloquent method Difference:
It's insert only single row at a time. whenever you want insert multiple rows/models then you need to run create() method in foreach loop or needs to use createMany() method.
All of them works same like create(). let suppose you want to insert 100 rows in database table then both will runs 100 insert queries under the hood.
It emits model events i.e. creating, created events etc.
It returns inserted model in result.
It's slower than insert() query builder method because it's handling a lot of computations, events pipelines during insertion.
Suggestion:
If you want to catch model event then must use eloquent(). If you want query optimization, fast insertion and doesn't have any concern with model events then user insert() method.
Related
In a nutshell, the title best discribes my question, but here I am showing the core of the problem.
I have two databases in my web application, One is MariaDB, the other is MongoDB, To give some context, the "user" table in MariaDB stores user information with column "id" it's primary key, there is another "badge" table which stores badge information with also column "id" it's primary key, at last there is "user_badge" collection in MongoDB having documents of fields
{_id, user_id, badge_id, date}
which just links the User with his/her Badges. This is what I meant by pseudo-relation, Unfortunately I don't know what is it called in this situation.
An example:
I want to query and get all users that have a badge with ID 1. So my pseudo-query should do something like "Select all fields from user table where badge_id in user_badge collection is 1". I highlighted like here because this is impossible to be done in a query (based on my knowledge) somehow a query ought to be made on the MongoDB database first then a second have to be made in the MariaDB database against the results of the former query.
Edit: My original question was about how to implement this in Yii2 PHP framework, but when I googled for sometime and I found out no information to do such a thing even in pure PHP, So I decide to end my edited question here, asking for a way to query between a table in an sql database and a collection in a no-sql database, Yet below I leave my old question which just asks for how to do this more specifically in the PHP framework. really if I knew how to do this in pure PHP I can just make a function somehow that does that in the framework if there wasn't any.
Obviously there cannot be a direct primarykey-foriegnkey relation between two database types but I overrided this issue by having a ::hasMany ActiveRecord method in my User Model, and that worked perfectly fine; When I have a User model between hands I just call $model->userBadges to get from MongoDB all documents having that User ID, also vice versa. The problem is when I do a Query involving this relation, I get error
Calling unknown method: yii\mongodb\ActiveQuery::getTableNameAndAlias()
Parts of my Application
User getUserBadges method in User model
public function getUserBadges(){
return $this->hasMany(UserBadge::className(), ['user_id' => 'id']);
}
UserBadge model extending yii\mongodb\ActiveRecord
class UserBadge extends ActiveRecord
{
public static function collectionName()
{
return 'user_badge';
}
public function attributes()
{
return ['_id', 'user_id', 'badge_id', 'date'];
}
public function getUser(){
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
public function getBadge(){
return $this->hasOne(Badge::className(), ['id' => 'badge_id']);
}
}
My query
$query = User::find()->joinWith(['userBadges']);
Edit: I figured out that the previous query is not really what I want, I simplified it to be clear but the real query that I want to do and you will get the point of why I am doing all of this is
$query = User::find()->joinWith(['userBadges'])->where(['badge_id' => 1]);
And with that I can get users from the user table who have a certain badge with id for example 1.
And here the code fails and throws the error stated above. After inspecting for sometime I found the API for the joinWith method
This method allows you to reuse existing relation definitions to perform JOIN queries. Based on the definition of the specified relation(s), the method will append one or multiple JOIN statements to the current query.
And here I knew that it's normal for this error to occur, In my query I am joining a document in a collection of the MongoDB database not a record in a table in a SQL database which definitely wouldn't work. I got stuck here and don't know what to exactly do, I am sticking to have user table in a SQL database and having the user_badge collection in a no-SQL database, what shall I do in such scenario? query on the no-SQL first and then query a SQL query against the result of the former query? or there is already a solution to such a problem in the methods of AcitveQuery? Or my Database structure is invalid?
Thanks in advance.
So after some good time I knew how to do it with the help of this question, where a SQL query is made against a PHP array.
So, first MongoDB will be queried and the results will be stored in an array, then A MariaDB SQL query will be made against the array generated from former query, I am pretty sure that this is not the best option; what if the result of the MongoDB query 100,000? well an array will be made with 100,000 entries, the SQL query will be made using also that 100,000 item array. Yet this is the best answer I could get (until now).
How to implement it in Yii2
// This line query from the MongoDB database and format the data returned well
$userBadges = UserBadge::find()->select(['user_id'])->where(['badge_id' => 1])->column();
// This line make the SQL query using the array generated from the former line
$userQuery = User::find()->where(['id' => $userBadges]);
I hope there can be a better answer for this question that someone can know, But I thought of sharing what I have reached so far.
I'm using laravel 5.4 I want to get record ids after I insert them in the table. here's data that I want to insert, it stored in array
$data = [
[
"count" => "100",
"start_date" => 1515628800
],
[
"count" => "102",
"start_date" => 1515715200
]
];
here I insert the array of items at once
\Auth::user()->schedule()->insert($data);
but this method returns boolean and I want to get ids(or all columns) of these new items after they been inserted, how should I do this? it doesn't matter if it will be done with eloquent or querybuilder. I already tried insertGetId method, but it doesn't seem to work with multidimensional array. if its not possible with laravel, what would be the best way to implement this?
Workaround: Select highest PK value and you should know what values they had. You might need locking to prevent a race with other users though.
edit:
LOCK TABLES schedule WRITE;
// Select last ID
UNLOCK TABLES;
the list of id's is then the last id - insert count
My approach is to generate the id's server side any time I run into this issue but you have to make sure the id's are unique. Also, you can do it for exactly the tables you need (not the entire database). Hope this helps.
$model = Person::findOne($person_id);
$model->status = $status;
$model->save();
or
Yii::$app->db->createCommand()->update('person',
['status'=>$status],
'person_id='.$person_id)
->execute();
In terms of performance, how this two snippet different from each other although the result is the same?
The firts is based on the fact the related active record is obtained by a preliminary select and then the change is performed by an update when the save() (and the related validation) method is invoked ..
The second don't perform a select for get the related activeRecord ..
and perform the update only
so the second should be more fast then the first ..
Using ActiveRecord (the first example) is generally more memory intensive (because of the object setup, teardown, validation etcetera).
The second one will be much faster but it does not validate the data. Most of the time you will want to work with a "small" set of ActiveRecords objects (that's why Yii2 has pagination in it's DataProviders). ActiveRecord is more powerful since you can traverse relations, use virtual attributes etc.
But for batch inserts the second one it is much better. And you can also use it like this to insert multiple rows in one query:
Yii::$app->db->createCommand()->batchInsert('tableName', ['id', 'title', 'created_at'], [
[1, 'title1', '2015-04-10'],
[2, 'title2', '2015-04-11'],
[3, 'title3', '2015-04-12'],
])->execute();
So I do a lot of calculations and at the end I have rates that need to be saved to existing rows in a table.
The array I have will be similar to the following:
[
<model_id> => [
'rate' => <some rate>
]
<model_id_2> => [
'rate' => <some other rate>
]
.....
]
Now obviously I could foreach through this array and do an update for each and every item in the array but I could end up with 100 update calls. Is there a way (through laravel's eloquent OR even a raw sql query) to do all these updates through one call?
You may try with Eloquent update() for multiple records update. Here is some code which I am using for update multiple records into the my table.
\App\Notification::where('to_id', '=', 0)
->update(['is_read' => 1]);
If you are worried about the request spent time you can handle this by firing an event and then queueing your listener/job, who will save your model, so it can be processed asynchronously. For examples, go to Laravel Docs for Queues
As long as I know you cannot update multiple rows on Laravel.
I am looking to use a Resource (destroy) post command to remove all rows within one column. The columns name is 'total' and it houses 'bigIntegers' but can be null. This is an SQLITE DB.
I have looked into using "truncate" but it seems that this removes all data from the table. I just want to clear the values within one particular column.
Is there an easy way using Eloquent in 4.2 to do this?
I'd try either with Eloquent:
YourModel::update([ 'total' => null ]);
Or the query builder:
DB::table('yourTable')->update([ 'total' => null ]);
Here's links to the docs:
Eloquent
Query Builder
DISCLAIMER: I'm not on my computer and can't check said solution, in the docs I found the update() always preceeded by a where() so it may be mandatory, but you can do where('id', '>', '0') or something. Also maybe null will build the actual SQL with nothing on it for a value, resulting in error, so maybe you actually need ['total' => 'null']
You don't need the where close. All rows in the table column total will be set to null.
Model::update(['total' => null]);