Laravel Eloquent: get dialog based on messages - laravel

I have messages table with structure like: id, to_id, from_id ...
I need to write Eloquent query that gives me dialogs for specific user as result. Every dialog should have one last message (no matter incoming or sent) and all ordered by ctreated_at desc.
For example getting whole dialog by id of companion:
$messages = Message::with(array_keys($fields->getRelations()))
->select($select)
->whereRaw('from_id = ? and to_id = ? ', [auth()->id(), $args['user_id']])
->orWhereRaw('from_id = ? and to_id = ? ', [$args['user_id'], auth()->id()])
->orderByDesc('created_at');
But before that i need a list of dialogs available to get.
Trying
$dialogUsers = Message::where('to_id', auth()->id())
->orWhere('from_id', auth()->id())
->select(['from_id', 'to_id'])
->distinct();
but i need to get messages too and in desc order

Related

Laravel: How to get duplicated records and group them together?

The code below is what I have to get all the duplicated products (by title) and group them together. It works perfectly fine. However, I so many records in my Products table and getting all of them causes a performance issue. Is there a way this could be optimised to avoid getting all records and group them in one query? Thank you.
$products = Product::all();
$groupsOfProducts = $products->groupBy('title');
$duplicatedProductsGrouped = [];
foreach($groupsOfProducts as $productGroup) {
$productIsDuplicated = $productGroup->count() > 1;
if($productIsDuplicated) {
$duplicatedProductsGrouped[] = $productGroup;
}
}
var_dump($duplicatedProductsGrouped);
You can use having in the group by:
Product::groupBy('title')->having(DB::raw('count(*)'), ">", "1")->select('title')->get()
And you will get the titles of the duplicates, then you can query the database with those titles
EDIT:
Please also try and see if this is faster
Product::getQuery()->whereIn('title', array_column( DB::select('select title from products group by title having count(*) > 1'), 'title'))->get();
with this line you will get ONLY the products that has a duplicate title, and so your Collection groupby should be faster to aggregate the records by the title
Let your database do the work. When you call Product::all(), you're getting every single record, then making PHP do the rest. Change your query to something like the following:
Product::selectRaw("title, COUNT(*) AS count")->groupBy("title")->get();
The result will be a Collection of Product instances with a title and count attribute, which you can access and determine duplicated ones:
$products = Product::selectRaw("title, COUNT(*) AS count")->groupBy("title")->get();
$duplicatedProducts = collect([]);
foreach($products AS $product){
if($product->count > 1){
$duplicatedProducts->push($product);
}
}
dd($duplicatedProducts);

Laravel: Reverse WHERE NOT IN - exclude any parent table that has children of id=XXX

Scenario is this: Need to get all sites which don't have licensee ID = XXX.
$data = DB::select("SELECT * FROM sites AS s
WHERE status = 'Existing Site' AND
$sharerId NOT IN (SELECT organisation_id
FROM licensees AS l
WHERE site_id = s.id)
order by siteName;") ;
This code does that fine.
But I get an array, which I can't filter on later using ::where(..), just in case the user wants to search for site name YYY. I've got a generic model method that handles all types of searches and sorts, I don't want to duplicate the code just for this.
$sharerId has the ID to exclude from the sites.
$data = $this->select($select)
->where('status', 'Existing Site')
->whereNotIn($sharerId,
Licensee::select('organisation_id')
->where('site_id', DB::raw('sites.id'))
)->get() ;
Tried this, but I really didn't expect it to work, and it didn't :-P
My crazy idea did work in the end:
$data = $this->select($select)
->where('status', 'Existing Site')
->whereNotIn(DB::raw($sharerId),
Licensee::select('organisation_id')
->where('site_id', DB::raw('sites.id'))) ;
All I needed was DB::raw($sharerId)

Delete 5 messages if two users have sent 6 messages to each other

I want to delete 5 messages in Ascending order from the table if any user has sent 6 messages to other user and show the 6th message. For example if Tapy has sent 6 messages to Nomi than first 5 messages will be deleted in ascending order and 6th message will be shown.
I have counted number of messages sent but can't find out the way to delete first 5 messages.
Table name :
t_chat_msg
The fields in the database are:
chat_msg_id
message
from_user_email
to_user_email
timestamp
Here is the model
function deletemessages($data)
{
$this->db->select('message as receiver,timestamp');
$this->db->from('t_chat_msg');
$this->db->where('from_user_email', $data['fromuser']);
$this->db->where('to_user_email', $data['touser']);
$this->db->order_by("timestamp", "asc");
$num=$this->db->count_all_results();
return $num;
}
Here is the controller
public function deletemessage()
{
$data = json_decode(file_get_contents('php://input'));
$touser = $data->{'touser'};
$fromuser = $data->{'fromuser'};
$data = array('touser' => $touser,
'fromuser' =>$fromuser);
$status=$this->um->deletemessage($data);
echo json_encode($status);
}
To get how much messages in total one user have sent to another use query
SELECT COUNT(*) AS K FROM t_chat_msg WHERE touser='$touser' AND fromuser='$fromuser'
Then you have a total number of messages, you can delete old one leaving desired amount of messages using query
DELETE FROM t_chat_msg ORDER BY timestamp ASC LIMIT $limit
IF PUT EVERYTHING TO FUNCTION
// $amt - amount of messages to keep
// $fromuser - message sender
// $touser - message recipient
function delete_old($amt,$fromuser,$touser)
{
$ma=mysqli_fetch_assoc(mysqli_query($db,"SELECT COUNT(*) AS K FROM t_chat_msg WHERE touser='$touser' AND fromuser='$fromuser'"));
$limit=$ma['K']-$amt;
mysqli_query($db,"DELETE FROM t_chat_msg ORDER BY timestamp ASC LIMIT $limit");
}
For codeigniter should work something like this
// $amt - amount of messages to keep
// $fromuser - message sender
// $touser - message recipient
function delete_old($amt,$fromuser,$touser)
{
$limit=$this->db->query("SELECT COUNT(*) FROM t_chat_msg WHERE touser='$touser' AND fromuser='$fromuser'")->row()-$amt;
$this->db->query("DELETE FROM t_chat_msg ORDER BY timestamp ASC LIMIT $limit");
}
I don't use it, but based on this it should work properly.

Magento - get order id from increment id

How do you get the Order Id from magento Order Increment Id?
I can use the following get the product id from SKU:
$product_id = Mage::getModel('catalog/product')->getIdBySku('ABCD1234');
The above example lets me get just the database entity_id of a product without loading everything. I want to achieve the same for order.
In a Magento model, the load method can take an optional second argument of what attribute to load by.
So, in your case, the following should work:
$order = Mage::getModel('sales/order')->load($incrementId, 'increment_id');
$id = $order->getId();
In more complex cases, e.g. where you want to load by a combination of fields, you can load a collection, and get the first element of the collection. In your case, you'd do it like this:
$order = Mage::getModel('sales/order')->getCollection()
->addFieldToFilter('increment_id', $increment_id)
->getFirstItem();
You can load an order from the IncrementId.
$orderIncrementId = "1000001";
$order = Mage::getModel('sales/order')->loadByIncrementId($orderIncrementId);
echo $order->getId();
If you want to fetch only order_id then simply use mysql query, if you want order_id in for loop, it is not load entire order object and it is very quick and fast, you don't need to load order object model.
$write = Mage::getSingleton('core/resource')->getConnection('core_read');
$result=$write->query("SELECT entity_id FROM `sales_flat_order` WHERE `increment_id` = 'your increment id' ");
$row = $result->fetch();
echo $row['entity_id'];

Filtering Results with CodeIgniter

I have two tables books and authors. Using CodeIgniter I would like users to be able to Filter results - for example, show results where author_id = 'x' and book_lang = 'y' and publication_year = '2000'. Filter criteria values come from user via drop-downs.
What's the best way to generate the query using codeigniter helper and binding etc?
For example, the query below will give me everything with author_id= 1. what if filters are a mix, for example; author_id = 1; language = 'all' (don’t put where clause on language) and publication year = 'all' also don’t put where clause.. Do I manually need to check for values and code or is there a codigniter helper method that allows filter to be removed from where clause if dropdown value is 'show all'?
$sql = "select * from AUTHORs a , BOOKS b where
a.AUTH_ID = b.BOOK_AUTH_ID
and b.BOOK_AUTH_ID = ?
and b.BOOK_LANGUAGE = ?
and b.PUB_YEAR = ? ";
$query = $this->db->query($sql, array ($author_id, $book_lang, $pub_year));
You should use Codeigniter's Active Record class to construct your query:
$this->db->select('*');
$this->db->from('AUTHORs a , BOOKS b');
$this->db->where('a.AUTH_ID', 'b.BOOK_AUTH_ID');
if ($author_id != 'all') $this->db->where('b.BOOK_AUTH_ID', $author_id);
if ($book_lang != 'all') $this->db->where('b.BOOK_LANGUAGE', $book_lang);
if ($pub_year != 'all') $this->db->where('b.PUB_YEAR', $pub_year);
$query = $this->db->get();
To read more about Codeigniter's Active Record class, visit the Docs:
http://codeigniter.com/user_guide/database/active_record.html

Resources