I'm using vinkla/instagram composer package in my Laravel to fetch Instagram posts in my app.
Since Instagram allows the package to call their API 200 times per hour I'm trying to save post links into database table. And this package fetches 20 latest posts and its attributes.
Here I'm trying to compare the link of posts fetched by vinkla/instagram composer package and already saved posts and insert only unique into to table.
Below is the code snippet:
$instagram = new Instagram('access-token');
$posts = $instagram->media(); //gets 20 latest insta posts of a user
$fromDBs = Insta::orderBy('id', 'desc')->take(20)->get(); //get last 20 rows from table
foreach( $posts as $post)
{
foreach( $fromDBs as $fromDB)
{
if($post->images->low_resolution->url != $fromDB->link)
{
$create = new Insta;
$create->link = $post->images->low_resolution->url;
$create->save();
}
}
}
With the above stated code the new links are inserted x10 times.
What would be the correct way to insert unique link once only.
There are firstOrCreate or firstOrNew helper functions on eloquent, so you can create it only if it does not exist in order to prevent duplicates. So instead of your check you can check this code:
foreach( $posts as $post)
{
Insta::firstOrCreate(['link' => $post->images->low_resolution->url]);
}
...
foreach( $posts as $post)
{
foreach( $fromDBs as $fromDB)
{
if($post->images->low_resolution->url != $fromDB->link)
{
$create = Insta::firstOrNew(['link' => $post->images->low_resolution->url]);
if(! $create->id ) $create->save();
}
}
}
Related
I have a controller API method where I insert many rows (around 4000 - 8000), before inserting a new row I also check if a venue with the same ame was added already in the zone sothat's another Elouent call, my issue is I usually get timeout errors becuase the row inserting takes too much, I use set_time_limit(0) but this seems too hacky.
I think the key is the validation check I do before inserting a new row.
//Check if there is a venue with same name and in the same zone already added
$alreadyAdded = Venue::where('name', $venue['name'])->whereHas('address', function ($query) use ($address){
$query->where('provinceOrState' , $address['provinceOrState']);
})->orWhere('venueId',$venue['venueId'])->first();
Is there a way I can improve the performance of this method ? This is my complete method call:
public function uploadIntoDatabase(Request $request)
{
set_time_limit(0);
$count = 0;
foreach($request->input('venuesToUpload') as $index => $venue)
{
//Check if there is a venue with same name and in the same zone already added
$alreadyAdded = Venue::where('name', $venue['name'])->whereHas('address', function ($query) use ($address){
$query->where('provinceOrState' , $address['provinceOrState']);
})->orWhere('venueId',$venue['venueId'])->first();
if(!$alreadyAdded)
{
$newVenue = new Venue();
$newVenue->name = $venue['name'];
$newVenue->save();
$count++;
}
}
return response()->json([
'message' => $count.' new venues uploaded to database',
]);
}
use only one request to add the venues
$newVenues = [];
$count = 0;
foreach($request->input('venuesToUpload') as $index => $venue) {
//Check if there is a venue with same name and in the same zone already added
$alreadyAdded = Venue::where('name', $venue['name'])->whereHas('address', function ($query) use ($address){
$query->where('provinceOrState' , $address['provinceOrState']);
})->orWhere('venueId',$venue['venueId'])->count();
if(!$alreadyAdded) {
$newVenues [] = ['name' => $venur['name'];
}
}
if ($newVenues) {
$count = count($newVenues);
Venue::insert($newVenues);
}
As for the verification part, change the first to count cause you dont need to recover the data, just the information that it exists. And since you're verifying with both name and id, you can do some custom query that verifies all values in one query using a static table made from the request inputs and joining on the existing venues table where venues.id = null.
I have posts and these posts can be saved by users to read later. I created this relation and I can save or delete them easily. The problem is I can't check if the post is saved or not in frontend. Now I wrote some code to handle this but it doesn't seem to work. here is my controller code:
$articleFlag = 1;
$userID = Auth::User()->id;
if (count($bestarticles) > 0) {
foreach ($bestarticles as $bestarticle) {
$saveddata = DB::table('savearticle')->where('user_id', $userID && 'article_id', $bestarticle);
if (count($saveddata) > 0) {
$articleFlag = 1;
} else {
$articleFlag = 2;
}
} //foeach endes here
} //first if endes here
and than I pass the $articleFlag to the view than checking it's value with an if
But the problem is, no matter what I do if (count($bestarticles) > 0) returns true and I get value 1 in view.
Does anybody have any idea what I might be missing?
Here is my user controller relationshio:
function savedarticle(){
return $this->belongsToMany('App\User', 'savearticle', 'user_id',
'article_id');
}
and here goes the functions that i use for saving and deleting:
function savethearticle(Article $article){
$this->savedarticle()->syncWithoutDetaching([$article->id]);
}
function removethearticle(Article $article){
$this->savedarticle()->detach([$article->id]);
}
But there is nothing you need to worry about. I'm able to delete and add.
Or is there another way to check for existing relationship in view or a better way to check it in controller and pass into view?
I am using Laravel 5.4.
It looks as though you have a Collection of Article models, and you're trying to determine whether it is related to the User or not.
If that's the case, I would suggest eager loading the User relation when you originally query the Article models. This has the advantage of using one query to load the relationship, rather than one per Article.
$userId = Auth::id();
$articles = Article::with(['savedarticle' => function ($query) use ($userId) {
return $query->where('user_id' => $userId);
}])->get();
With this Collection, because we have loaded specifically the currently authenticated User, you can then proceed knowing that if the savedarticle relation has a count of 1, that the User relation exists.
foreach ($articles as $article) {
if ($article->savedarticle->count()) {
// User has already saved article
} else {
// User has not saved article
}
}
Should you not be passing the id of bestarticle in the Where clause? Also, it requires a ->get() to actually fire the request off to the database and run the query.
$saveddata = DB::table('savearticle')->where('user_id', $userID && 'article_id', $bestarticle);
Should be
$saveddata = DB::table('savearticle')->where('user_id', $userID && 'article_id', $bestarticle->id)->get();
I am using eloquent to pull a list of App\Post's from my database and deleting their file contents from my server.
I am traversing through the list and processing a delete action, on success I want to store a value to the respective App\Post but I am getting this error:
Method save does not exist.
Here is my code:
$posts_to_purge = Post::where('post_date', '<', \Carbon\Carbon::now()->subDays(7)->toDateString())->get();
if(count($posts_to_purge) > 0)
{
foreach ($posts_to_purge as $post) {
$directory = storage_path() . '/' . $post->post_date;
$deleted_folder = File::deleteDirectory($directory);
if($deleted_folder)
{
// 'purged' is a column in my Post table
$post->purged = 1;
}
else
{
Log::error('Unable to delete \''.$directory.'\' directory');
}
} // end foreach loop
// Update collection with purged posts
$posts_to_purge->save();
}
A side question to this... is this the most efficient way to do this? As I only want to update SOME records in the collection.. should I create a separate collection and save that only?
Collections don't have really have the power to interact with the database in Laravel. You are able to define a custom collection class with a save() method however there is a simple way to do what you want.
$posts_to_purge = Post::where('post_date', '<', \Carbon\Carbon::now()->subDays(7)->toDateString())->get();
if(count($posts_to_purge) > 0)
{
foreach ($posts_to_purge as $post) {
$directory = storage_path() . '/' . $post->post_date;
$deleted_folder = File::deleteDirectory($directory);
if($deleted_folder)
{
// 'purged' is a column in my Post table
$post->purged = 1;
$post->save ();
}
else
{
Log::error('Unable to delete \''.$directory.'\' directory');
}
} // end foreach loop
// Update collection with purged posts
$posts_to_purge->save();
}
Yes this does do one query per updated model, however updates by primary key are very fast.
If you were super committed to using one query, you could simply save each updated Post's ID to an array and do something like Post::whereIn ('id', $updated_ids)->update(['purged' => 1]);
I have a table named 'categories' with uniqueness constraint on 'category_name' in my application, I want to inset multiple rows in 'categories'.
Bad Solution:
foreach($categories as $category) {
Category::firstOrCreate(array('category_name' => $category['name']));
}
This can be a solution but this is not a good one.The issue is when there will be hunders or thousands of record, this will make a lot of queries to database. which is not good.
Comparativel berter Solution
foreach($categories as $category){
$cats[] = array('category_name' => $category['name']);
}
Category::insert($cats);
But when I try to insert a duplicate 'category_name', it throws an exception and none of category name is inserted.
I know that we can use INSERT IGNORE but I'm looking for some build in laravel solution.
I think it won't be possible because in 2nd case one query will be executed so even if you catch any error no data will be inserted because SQL server refuse it because of unique constraint. I don't think Laravel can handle it.
Probably something like this is compromise to solve it quicker:
foreach($categories as $category){
$names[] = $category['name']
}
$dups = Category::whereIn('name', $names)->lists('name');
if ($dups) {
// here you can log or display message that some categories won't be inserted
}
$namesIns = [];
$cat = [];
foreach($categories as $category){
$item = ['category_name' => $category['name']];
if (!in_array($category['name'], $dups) && !in_array($item, $cat)) {
$cat[] = $item;
$namesIns[] = $category['name'];
}
}
Category::insert($cat);
$ids = Category::whereIn('name', $namesIns)->lists('id');
I have a post model, a user model and a comment model.
My users can post posts and also can comment to posts.
I want to get the comments of posts with posts but, my users can also block users too.
I mean, if the active user has some other blocked users, and if the comments of post has comments created by these users, I have to exclude them.
And here comes the problem.
$posts = $user()->posts()->get();
$blockedUserIdentifiers = (array) $viewer->getBlockedUserIdentifiers();
$posts->with(array('comments' => function($query) use ($blockedUserIdentifiers)
{
if( ! empty($blockedUserIdentifiers))
$query->whereNotIn('user_id', $blockedUserIdentifiers);
}))->with('user'); // ? Ups?
I want to use relationships of posts and also comments, because the work is not finished here. But if I use foreach on posts array, it will be very strange to continue and; if I use foreach on posts object, I is hard for me to continue.
Because i have blockedUser condition, I can not eager load too.
What is the best practice of my case or, how should I add $comments result object to $posts object like laravel does?
Or how can I continue to add relationship results to that result?
Putting constraints on multiple relationships with with().
$posts->with(array('comments' => function($query) use ($blockedUserIdentifiers)
{
// if( ! empty($blockedUserIdentifiers))
// $query->whereNotIn('user_id', $blockedUserIdentifiers);
}, 'comments.user', function($query) use ($blockedUserIdentifiers)
{
// Constraints on the users can go here
if( ! empty($blockedUserIdentifiers))
$query->whereNotIn('id', $blockedUserIdentifiers);
}))->get();
Or doing it while echoing.
foreach($posts as $post) {
// If you want to keep your relationships clean, you can just not echo the post instead
if(array_search($post->user_id, $blockedUserIdentifiers) !== false) {
continue;
}
echo $post->content;
foreach($post->comments as $comment) {
echo $comment->user;
echo $comment->content;
}
}