How to bulk insert with RedBeanPhp? - php

I was hoping for an example on how to bulk insert new "beans" in readbeanphp without looping over each instance.
It shows an example creating and saving a beans here: http://redbeanphp.com/manual/create_a_bean
It makes mention of storeAll($beans) method, but I am unsure exactly how I am suppose to format the data in $beans.
I have tried googling for this and can not find anything related to bulk inserts. Maybe I have searched for the wrong terms.
I am new to this ORM, any help with would appreciated, thanks!

You are definitely right on track. Create a new bean using $bean=R::dispense('bean'); or multiple beans as an array $beans=R::dispense('bean',5);
Then you populate the beans with data:
$bean->title='Hello World!';
//or with an array
$beans[0]->title='Hello World!';
$beans[1]->title='Hello World! Bean 1';
//etc
Then store the bean(s):
R::store($bean);
//or
R::storeAll($beans);
All the beans must be the same type if you have multiples as far as I know, so you can do something like:
$beans=array();
$beans[]=R::dispense('bean');
$beans[]=R::dispense('bean');
$beans[0]->title='Hello World!';
$beans[1]->title='Hello World!1';
R::storeAll($beans);
I could be wrong about that though. The main thing is that this is all a typical ORM, but redbean also supports regular SQL if you need to use it. Hope that helps!

Some real data behind this approach.
FIRST APPROACH.
foreach item found
$bean = R::dispense('bean');
$bean->title = "hello";
R::store("bean");
time taken for 5660 rows = 43s on my mac
SECOND APPROACH.
$beans=array();
$beans[]=R::dispense('bean');
$beans[]=R::dispense('bean');
$beans[0]->title='Hello World!';
$beans[1]->title='Hello World!1';
R::storeAll($beans);
For 5660 rows, 46s. The storeAll is where all the time is. So its taking ages to store these beans.
THIRD APPROACH
$beans=R::dispense('bean',5560);
for loop
$bean[$i]->title = "hello world";
end for
R::storeAll($beans);
For 5660 rows 45s.
Result. None of these approaches are any quicker. : (
RedBean Transactions didn't seem to make this any quicker either
From the creator of RedBean https://stackoverflow.com/a/18811996/445492 Bulk Insert is not supported, use pure sql.
FOURTH APPROACH
for loop
R::exec("insert into bean(title) values (1,'hello world')");
end for
for 5660 rows 7.3s <----- WOW
(please note: I am actually doing some stuff prior so all these results are -4.3 seconds.)

Hence every bean needs to be created first and the method to create a bean is dispense
$bean = R::dispense('customers');
$bean->name = "John";
R::store($bean);
$bean->name = "Walter"
R::store($bean);
the code above creates only one bean even after storing it. Still $bean refers to the same object, so for each record you have to create a new been by using dispense method.
Luckily we have storeAll method that stores all the beans but it requires an array of beans. So we create a bean in each iteration and push it to the array and then at the end of loop we just pass that array to storeAll function.
//create empty array
$beans = array();
//for each customer post create a new bean as a row/record
foreach ($post as $customer) {
$bean = R::dispense('customers');
//assign column values
$bean->firstName = $customer['first_name'];
$bean->lastName = $customer['last_name'];
//push row to array
$beans[] = $bean;
}
//store the whole array of beans at once
R::storeAll($beans);

In the approaches 1, 2 and 3 suggested by John Ballinger, one way to optimize the run time is to put all the insertions performed by storeAll($beans) inside one database transaction. This could be done as follows: replace the line "R::storeAll($beans)" by the following three lines:
R::begin();
R::storeAll($beans);
R::commit();
This approach reduces dramatically the run time when the array $beans is large, AND is not necessary to use SQL "explicitly".

Related

How to replace collection in query result Mongo

I queried to get info from a table with a manytomany relationship like this
$userList = UserListing::where('user_id', $user->id)->with("objects")->paginate(10);
Now, i want to limit the amount of results in the "Objects" table, but at the same time i want to know how many objects are in total.
$userList = UserListing::where('user_id', $user->id)->with(["objects"=> function($query) {
$query->take(2);
}])->paginate(10);
But by doing this, i can't get the total of objects since i limited it to 2, then i tried to process the info like this
$userList = UserListing::where('user_id', $user->id)->with("objects")->paginate(10);
foreach ($userList as $key => $value) {
$l = count($value["objects"]);
$value["objects"] = $value["objects"]->take(2);
$value["number_objects"] = $l;
}
But apparently this did not replace the collection value["objects"], since it still returned 3 objects, despite supposedly being reduced with $value["objects"] = $value["objects"]->take(2);. How can i replace the collection with the reduced one?
So, i kept investigating, and noted that userList was a LengthAwarePaginator object, which by property apparently is inmutable in its original fields(Meaning you can add new ones, but not delete/modify the already existent). Knowing this, i searched a little more and found this answer:
https://stackoverflow.com/a/49133519/7228093
Which basically creates a new LenghtAwarePaginator from the original one, allowing you to modify the fields. If someone finds in this situation, this may be a good option(The transform method of collections did not work by the way, only this one).

Is there a way to reduce multiple comparison with similar parameters?

I am using php as backend of a website. I made a form of around 50 questions and I have to store it in a table every single time I answer something different.
So my first newbie thought was to compare the $request->Question1 with the $table->Question1 and if this is different, I create a new record on the History table.
But it took my to an endless and nothing good looking comparison lines, repeating some of the code like:
if ($table->Question1 != $request->Question1)
{
$Question = new HistoryTable();
$Question ->reason = 'Change Answer';
$Question ->column_affected = 'Question1';
$Question ->old_value = $table->Question1;
$Question ->new_value = $request->Question1;
$Question ->created_at = Carbon::now();
$Question ->save();
}
Is there a way it could be reduced ? I was thinking in using a form, but I have to mention I have columns/values as Question23_1 and Question23_2 ... but they are the same name as in table
Thanks in advance!
Well, some might suggest a different database-table architecture – one that does not involve these "repeating groups." But there might be other compelling reasons to have done what you did.
Maybe you could retrieve the record, instead of as a "PHP object," as an array ("hash" ...) indexed by field-name. Then you could use interpolation of strings such as "Question$x_$y" ... substituting the values of $x and $y to obtain the name of the field whose value you are now interested in ...

using array_search VS storing data in array as both index

What is better and fast:
$objectTypes = array(
1=>'Content',2=>'Taxonomy',3=>'Ad',4=>'Issue'
);
ID: $objectTypes[1];
Title: array_search('Content',$objectTypes);
VS
$objectTypes = array(
1=>'Content',2=>'Taxonomy',3=>'Ad',4=>'Issue',
'Content'=>1,'Taxonomy'=>2,'Ad'=>3,'Issue'=>4);
ID: $objectTypes[1];
Title: $objectTypes['Content'];
IN first I use array_search to get the id of object.
In second I just store it other way round.
Mostly the object is not going to change and it won't have more than 5-10 types
I need to store the object id and title
I am just curious for use of the method vs large array
ofcourse when i use it in class, i'll use proper function to get/set
Performance is first preference, but a good coding style and optimum use of class objects/files is also important.
The second one is not recommended. There is no point in saving the same data twice and think about all the wasted time populating the unnecessary data. So to answer your question array_search will do you better

Laravel - Single query then splitting Vs Two queries

I am using laravel framework and I need to get 2 arrays, one with premium themes and one with free themes.. so I would do:
$premium_themes = \App\Theme::where('premium', '=', '1')->get();
$free_themes = \App\Theme::where('premium', '=', '0')->get();
This will work Ok, but will perform two queries on the database. Since I'm an optimization geek, I think it might be better to have a single query... which I would get all themes by using:
$themes = \App\Theme::all();
And then I'd to process this in php to split based on the theme premium property.
So I have 2 questions:
1) A single query is better than 2 queries in this case, or am I over-thinking this?
2) Is there a fast simple way to split the resulting collection into two collections based on the premium property? (I know Laravel has many shortcuts but I'm still new to the framework)
Single query would be better as both of the queries will go over all the rows in the database. Except the 2 queries to split them will go over them for a second time.
You can simply filter them like so;
The simple one line solution $themes = \App\Theme::all()->groupBy('premium');.
Or into separate collections if you need to filter by another element etc just add more to the following;
$themes = \App\Theme::all();
$premium = new Collection;
$free = new Collection;
$themes->each(function ($item) use ($premium, $free){
if($item->premium == '1'){
$premium->push($item);
}
else {
$free->push($item);
}
});
And your items will be filtered into the relevant Collection. Be sure you use the Collection class at the top.
The only reason I can think to keep it as separate queries would be if you need to paginate the data - not something you can do easily if its all mixed together.
A "short cut" would be to use the collection filter() method, I put short cut in quotes because it's not short per-se, more syntatic sugar - but Larvel is nothing if not full of sugar so why not?
Code would look something like this:
$allThemes = \App\Theme::all();
$premiumThemes = $allThemes->filter(function($theme)
{
return $theme->premium;
});
$freeThemes = $allThemes->filter(function($theme)
{
return !$theme->premium;
});
Edit: I'd recommend using Matt Burrow's answer, but I'll leave mine here as the solution is different.

drupal--why $node->taxonomy is an array

someone wrote this code.
foreach ($node->taxonomy as $term) {
$tids[] = 't.tid = %d';
$args[] = $term->tid;
}
how he knows that in foreach "$node->taxonomy" is an array? and when i loop it,
foreach ($node->taxonomy as $term) {
}
the output that i get will be the $term's value. i don't know how it is change into the 't.tid = %d' and $term->tid. thank you.
In Drupal-related code, a $node is almost always an object produced by the node_load() function. Since every module has the opportunity to add its own properties to this object, it's very hard to find a central documentation of these properties.
By experience and by variable inspection, seasoned Drupal developers know that when set $node->taxonomy is always an array of term object (as returned by the taxonomy_get_term() function) indexed by their respective ids (named tids, for Term ID). This array is set by the taxonomy_nodeapi() function when $op == 'load' and is produced by the taxonomy_get_terms() function.
The question give little information but we can guess that the loop is meant to build two arrays used to generate a database query that filter on the tid column matching those of the $node object. Because the terms' data is already stored in the items of $node->taxonomy, let's hope that this query is not used to re-load the terms to display some of their name and/or description. Collecting 't.tid = %d' is probably a bad idea, the query would be better build with a single "tid in (". db_placeholder($args) .")" WHERE clause after collecting all the tids in $args.
The question is very unclear. All Items under the node object are arrays. You can check it yourself bu using:
print_r($node);
die;
Or using any PHP debugger.
for the foreach, It is very simple foreach... I don't understand what is the problem with that.
t.tid is simply an SQL query. %d is a placeholder for $args[], which consists of $term->tid. It's like this structure: PDO connections.

Categories