How do I modify/enrich an Eloquent collection? - arrays

I'm using eloquent relationships.
When I call $carcollection = $owner->cars()->get(); I have a collection to work with. So let's say that I have, for this particular owner, retrieved three cars. The collection is a collection of three arrays. Each array describes the car.
This is all working fine.
Now I want to add more attributes to the array, without breaking the collection. The additional attributes will come from a different source, in fact another model (e.g. servicehistory)
Either I retrieve the other model and then try merge() them, or I try manipulate the arrays within the collection without breaking the collection.
All this activity is taking place in my controller.
Is one way better than another, or is there a totally different approach I could use.... perhaps this logic belongs in the model themselves? Looking for some pointers :).

Just to be specific, if you do $owner->cars()->get(); you have a collection of Car Models, not array.
That have been said, you can totally load another relation on you Car model, using
$carcollection = $owner->cars()->with('servicehistory')->get();
$carcollection->first()->servicehistory;

You can try to use the transform method of the collection.
$cars = $owner->cars()->get();
$allServiceHistory = $this->getAllService();
$cars->transform(function($car) use($allServiceHistory) {
// you can do whatever you want here
$car->someAttribute = $allServiceHistory->find(...):
// or
$car->otherAttribute = ServiceHistoryModel::whereCarId($car->getKey())->get();
});
And this way, the $cars collection will be mutated to whatever you want.
Of course, it would be wiser to lazy load the data instead of falling into an n+1 queries situation.

Related

FireStore and maps/arrays, document-list to array in Kotlin

I've finally started to understand a lot of info regarding FireStore, but I'm wondering if I can get some assistance.
If I had a setup similar to or like this:
          races
                Android
                      name: Android
                      size: medium
                       stats          <---- this is the map
                                str: 10
                                sex: 12.... (more values)
How would I parse this? I am looking to make specific TextViews apply values found in the database so that I can simply update the database and my app will populate those values so that hard coding and code updating won't be nearly as troublesome in the future.
I currently use something like this:
val androidRef = db.collection("races").document("Android")
androidRef.get().addOnSuccessListener { document ->
if (document != null) {
oneOfTheTextViews.text = document.getString("str")
} else {
}
The issue is currently I can only seem to access from collection (races) / document (android) / then a single field (I have "str" set as a single field, not part of a map or array)
What would the best practice be to do this? Should I not nest them at all? And if I can reference said nesting/mapping/array, what functions need to be called? (To be clear, I am not asking only whether or not it is possible - the reference guides and documents allude to such - but what property/class/method/etc needs to be called in order to access only one of those values or point to one of those values?).
Second question: Is there a way to get a list of document names? If I have several races, and simply want to make a spinner or recycler view based on document names as part of a collection, can I read that to the app?
What would the best practice be to do this?
If you want to get the value of your str property which is nested within your stats map, please change the following line of code:
oneOfTheTextViews.text = document.getString("str")
to
oneOfTheTextViews.text = document.getString("stats.str")
If your str property is a number and not a String, then instead of the above line of code please use this one:
oneOfTheTextViews.text = document.getLong("stats.str")
Should I not nest them at all?
No, you can nest as many properties as you want within a Map.
Is there a way to get a list of document names?
Yes, simply iterate the collection and get the document ids using getId() function.

Are there any objective reasons why it is better to not call functions in Angularjs Views to display data?

To make a long story short, in our application at work, we have a function that creates multiple objects that inherit methods from a prototype.
As such:
function MileCounter(totalMilesRan, numOfDaysToRunThem) {
this.totalMilesRan = totalMilesRan;
this.numOfDaysToRunThem = numOfDaysToRunThem;
};
MileCounter.prototype.avgMilesPerDay = function() {
return (this.totalMilesRan/this.numOfDaysToRunThem);
}
And then in the view, this is called like this:
<div> {{mileObj.avgMilesPerDay()}} </div>
The disagreement comes from their belief that the average should be provided to the mileObj in the controller so the average can be called in the view just as they would to get moneyObj.totalMilesRun as:
<div> {{mileObj.avgMilesPerDay}} </div>
Something to keep in mind is that the actual objects in question have many more properties than just two and the number of objects being created is usually in the dozens but could eventually sky rocket into the hundreds or even thousands.
My Coworkers believe that the view should not be concerned at all with calculating data and should only be concerned with displaying it.
My Question: Is there an objective reason why it would be better to add the avgMilesPerDay value directly to each object, rather than just calling a prototype method to handle it? It is my understanding that adding a bunch of properties to objects could eventually be a drag on memory when there are enough objects being created, with enough properties on each one, and that having simple prototype methods could help ease that burden.
Advantages of calling a function:
less memory usage
more encapsulation: changing the value of totalMilesRan or numOfDaysToRunThem automatically changes the value of the average
Advantages of adding a field for the average:
slightly more efficient: the average doesn't need to be computed again and again
I would keep using the function from the view unless you have a performance problem, and have proven that it comes from the function call, and it can't be solved in another way (like one-time binding for example).

Backbone: Does Collection#get return a copy of the model or the model object itself?

I've been having some difficulty understanding exactly what happens when a model is manipulated in Backbone.
1) When calling #get on a Collection to "grab" a model, is the model the same model as the Collection's model? (e.g., updating the model will update the Collection's model)
2) If a model is added to various collections, do all of those collections contain the actual model (or a "copy" of the model)? It seems to me that it's the "copy" because when I try to destroy a model that has been added to various collections, not all the models in the various collections are destroyed.
Thanks! Appreciate any insights.
Like every other object in Javascript, Backbone objects are 'passed by a copy of the reference'. The best way to think about this is that javascript has a piece of data in memory, and variables are nothing more than pointers to those bits of data. When you set one variable equal to another, what you really get is two copies of the pointer, both pointing at the same piece of data in memory. So, applying this to your question:
Yes. When you 'get' the model, what you 'get' from backbone is a
pointer to the place in memory where the object is stored. Now you
have two pointers (one in the collection and one in your variable), and you can perform operations on either of them
and either will perform that operation on the same piece of data in
memory.
Kind of. Each collection has, again, a pointer to the same
object/model. When you remove that pointer from a collection, the
other pointers remain pointing to the same piece of memory, and that
memory is not erased, because it's still being pointed at from other
collections. model.destroy() will trigger a destroy event on both
the model and the collection it is holding a pointer to in it's
collection attribute. However, the model can not hold pointers
to multiple collections if it is a part of more than one collection.
So on your destroy event, it is removed only from the collection it was last assigned to - the one it holds in the model.collection attribute. Ordinarily, when no variables are holding pointers to the piece of data in memory, that memory will be erased, however, in this case, because your other collections have pointers to the model, the model remains in memory as a part of those collections.

Backbone: pluck models with an array of IDs, and save them

So I have an array of IDs:
var myIDs = [1,5,9];
I have a collection that I want to search through, and pluck from. I thought I could do something like the following:
var searchResults = myCollection.where({"uID" : myIDs});
Of course that won't work, but there must be a way to achieve something similar.
Once I have the selected models, the plan is to edit the contents of, then save. Am I correct in assuming I can save the whole batch by doing the following?
myCollection.reset(searchResults);
I'm a total n00b to Backbone, obviously.
You can use Collection.filter to compare each item against the array:
var searchResults = myCollection.filter(function(model) {
return myIDs.indexOf(model.id) != -1;
});
("Where" is like a special case of "filter", with a specific iterator -- it compares the properties of each model with the hash set you provide.)
As far as saving, if you mean replacing the items in the collection, then yes, you can use reset for that. (Note that "save" in Backbone parlance normally means syncing model updates back to the server.)

Backbone collection: Retrieve distinct values of a collection

I have backbone collection of models and would like to retrieve the distinct values of a certain property
If I have loaded data like the following into my collection:
[{brand:'audi',id:'1234'},
{brand:'audi',id:'3456'},
{brand:'bmw',id:'3456'}]
I would now want to get the distinct brands from the collection. The result should be:
['audi','bmw']
Looking at the Backbone and Underscore API I don't see anything obvious to achieve this.
My current approach would be to use a library like jslinq
Am I missing anything obvious or does somebody have a better suggestion than jslinq?
You can use pluck and then use uniq (example: http://jsfiddle.net/sCVyN/5/)
pluck
A convenient version of what is perhaps the most common use-case for
map: extracting a list of property values.
uniq
Produces a duplicate-free version of the array, using === to test
object equality. If you know in advance that the array is sorted,
passing true for isSorted will run a much faster algorithm. If you
want to compute unique items based on a transformation, pass an
iterator function.

Resources