Sort Collection By id set - laravel

I have an array of ids that i want to sort a given column by them in the collection.
For example,
$suppliersOrder = [8,7,5,1,3,4];
$items = Items::get()->sortBy(function($model) use ($suppliersOrder) {
return array_search($model->supplier_id, $suppliersOrder);
})->values();
This acts like ordering items as [1,3,4,5,7,8] instead of the given order. And if I try sortByDesc, likewise [8,7,5,4,3,1] but I couldn't figure out the way to actually sort them as my given array's order.
My ultimate goal is then running $items->groupBy('supplier.name') so I can have my desired order.
What Alexander Villalobos suggested in the comments, I changed my code like this:
$items = Items::get()->sortBy(function($model) use ($suppliersOrder) {
return rsort($model->supplier_id, $suppliersOrder);
});
Indirect modification of overloaded property App\Item::$supplier_id has no effect

$suppliersOrder = [8,7,5,1,3,4];
$items = Items::get()->sortBy(function($row,$key) use ($suppliersOrder) {
return array_search($row->supplier_id, $suppliersOrder);
});
This should give you sorted collection of items by the order you described in $suppliersOrder. As per Laravel docs, the parameters to the callback function include one being the row for the collection and another being the key of that row in the collection.

Related

How can i sort a laravel's elequent list by another ids

I have a challenge that if I want to sort the records when getting using Laravel's ORM based on a list of IDs, how should I do it?!!!!!!!
I mean :
Suppose we have a table called users, which contains 100 records and each record has a unique ID.
We also have an array of IDs.
$ids = [4,1,2,3]
Now I want to get the list of users, but only the users who are first in the ids array and secondly according to the same order as they are listed in this array.
User::whereIn('id' , $Ids)->sortBy('id',$ids)->get();
Can you think of a solution to do this?
User::whereIn('id' , $Ids)->sortBy('id',$ids)->get();
The collections sortBy() function can take a custom call back this way:
$users = User::whereIn('id', $Ids)->get()
->sortBy(function($user, $key) use($ids) {
return array_search($user->id, $ids);
});
This will sort your collection according to the given array.
You can also reference the docs for more information.
Note that the sortBy() function must act upon a collection, which means that the get() function must come before it.

How to check if collection's column matches an array

Model CustomerDocuments holds customer docs, doc_id is a column in this model that signifies which document is there.
I have an array of needed document IDs, say $neededDocs = [1,2,3].
How do I check if my collection CustomerDocuments contains $neededDocs in each item of this collection.
if all $neededDocsare present in each CustomerDocuments.doc_id then return true, else, false.
I would like to preform this with collection->contains as follows:
CustomersDocuments::where('customer_id', $customer->id)
->contains('doc_id',$required_onboarding_docs)
->get();
Yet this syntax is wrong
I think you could probably achieve this with something like the following:
$documents = CustomersDocuments::where('customer_id', $customer->id)
->get()
->pluck('doc_id')
->toArray();
The above will output an array with all the doc_id.
return $documents == $neededDocs;
You could then just compare it with your $neededDocs array.
Edit: If you, however, want to check that each row in your collection contains a doc_id that is present in $neededDocs, you could do it like this:
$collection = CustomersDocuments::where('customer_id', $customer->id)->get();
return $collection->contains(function($value, $key) use ($neededDocs) {
return in_array($value->doc_id, $neededDocs);
});
I am not entirely sure which one you want, but these should do the trick.

Laravel Sum a Collection with multiple items

I have a model SettlementEntries that has a relation to a sub table return $this->hasMany('App\Online', 'entry_id');
When trying to fetch one single Entry i'm able to sum my collection like in the example below.
$item = SettlementEntries::find($id);
$item->Online->sum('field'); // returns the correct sum
My problem starts when the $id is an array, so my result contains 2 SettlementEntries.
$items = SettlementEntries::find($ids);
$items->Online->sum('field'); <- returns zero
What is the correct way to retrieve those sums?
Laravel's Collection makes this very easy, by using dot notation. Some examples here.
The simple way (dot notation):
$sum = $items->sum('Online.field');
More explicit (callback):
Or, if you want to be more explicit, e.g. using conditions/filters: provide a Closure:
$sum = $items->sum(function($item) {
return $item->Online->sum('field');
});

Sorting a NotesDocumentCollection based on a date field in SSJS

Using Server side javascript, I need to sort a NotesDcumentCollection based on a field in the collection containing a date when the documents was created or any built in field when the documents was created.
It would be nice if the function could take a sort option parameter so I could put in if I want the result back in ascending or descending order.
the reason I need this is because I use database.getModifiedDocuments() which returns an unsorted notesdocumentcollection. I need to return the documents in descending order.
The following code is a modified snippet from openNTF which returns the collection in ascending order.
function sortColByDateItem(dc:NotesDocumentCollection, iName:String) {
try{
var rl:java.util.Vector = new java.util.Vector();
var tm:java.util.TreeMap = new java.util.TreeMap();
var doc:NotesNotesDocument = dc.getFirstDocument();
while (doc != null) {
tm.put(doc.getItemValueDateTimeArray(iName)[0].toJavaDate(), doc);
doc = dc.getNextDocument(doc);
}
var tCol:java.util.Collection = tm.values();
var tIt:java.util.Iterator = tCol.iterator();
while (tIt.hasNext()) {
rl.add(tIt.next());
}
return rl;
}catch(e){
}
}
When you construct the TreeMap, pass a Comparator to the constructor. This allows you to define custom sorting instead of "natural" sorting, which by default sorts ascending. Alternatively, you can call descendingMap against the TreeMap to return a clone in reverse order.
This is a very expensive methodology if you are dealing with large number of documents. I mostly use NotesViewEntrycollection (always sorted according to the source view) or view navigator.
For large databases, you may use a view, sorted according to the modified date and navigate through entries of that view until the most recent date your code has been executed (which you have to save it somewhere).
For smaller operations, Tim's method is great!

Rearranging active record elements in Yii

I am using a CDbCriteria with its own conditions, with & order clauses. However, the order i want to give to the elements in the array is way too complex to specify in the order clause.
The solution i have in mind consists of obtaining the active records with the defined criteria like this
$theModelsINeed = MyModel::model()->findAll($criteria);
and then rearrange the order from my php code. How can i do this? I mean, i know how to iterate through its elements, but i donĀ“t know if it is possible to actually change them.
I have been looking into this link about populating active records, but it seems quite complicated and maybe someone could have some better advice.
Thanks
There is nothing special about Yii's active records. The find family of methods will return an array of objects, and you can sort this array like any other array in PHP.
If you have complex sort criteria, this means that probably the best tool for this is usort. Since you will be dealing with objects, your user-defined comparison functions will look something like this:
function compare($x, $y)
{
// First sort criterion: $obj->Name
if ($x->Name != $y->Name) {
return $x->Name < $y->Name ? -1 : 1; // this is an ascending sort
}
// Second sort criterion: $obj->Age
if ($x->Age != $y->Age) {
return $x->Age < $y->Age ? 1 : -1; // this is a descending sort
}
// Add more criteria here
return 0; // if we get this far, the items are equal
}
If you do want to get an array as a result, you can use this method for fetching data that supports dbCriteria:
$model = MyModel::model()->myScope();
$model->dbCriteria->condition .= " AND date BETWEEN :d1 AND :d2";
$model->dbCriteria->order = 'field1 ASC, field2 DESC';
$model->dbCriteria->params = array(':d1'=>$d1, ':d2'=>$d2);
$theModelsINeed = $model->getCommandBuilder()
->createFindCommand($model->tableSchema, $model->dbCriteria)
->queryAll();
The above example shows using a defined scope and modifying the condition with named parameters.
If you don't need Active Record, you could also look into Query Builder, but the above method has worked pretty well for me when I want to use AR but need an array for my result.

Resources