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.
Related
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.
I fetch the data from a server and some items have a specific attribute others don't. I need to sort data according to this specific attribute and I am using sortBy package but of course it doesn't work properly because when it tries to sort data and doesn't find the attribute, it is broken.
myItems.sort(sortBy('specificAttr'))
Basically, what I did (think of inside of a loop):
if(!myItems.specificAttr) {myItems.speficificAttr = 0);
I know it doesn't make sense at all, but I don't know what I can do.
Do you have any advice with code examples?
Using lodash's sortBy
Lodash handles this case out of the box. If it can't find the attribute, it gets pushed to the end of the sorted array.
var users = [
{ 'age': 48 },
{ 'user': 'barney', 'age': 36 },
{ 'user': 'fred', 'age': 40 },
{ 'user': 'barney', 'age': 34 }
];
_.sortBy(users, [(o) => { return o.user; }]);
// => objects for barney, barney, fred, and no-name in that order
_.sortBy(users, ['user']);
// => objects for barney, barney, fred, and no-name in that order
If you're using some other library's sortBy, check the documentation to see if there's an optional second argument that would allow you to customize the attribute getter function.
Rolling your own
If you're implementing your own sorting algorithm, simply do a check like if myItem.specificAttr to check if the attribute exists while you're doing the actual sorting (rather than prior sorting, as you described in your example).
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.
I use to use the where method from the Collections in backbone. But I don't see how to fetch this result:
MyCollection.Group[x].id
As you can guess, MyCollection is the collection, Group is an array, and id is the field I would like to match for a specific value, something like:
MyCollection.findWhere(Group[x].id: 34);
I have seen the "contains" function of underscore but it doesn't seems to work with associative arrays
Is there a way to do it or should we parse the collection manually using Javascript ?
Collection.where and Collection.findWhere are convenience functions for simple filters. In your case, you would use the more complex Collection.find (proxied to _.find)
find _.find(list, iterator, [context])
Looks through each value in the list, returning the first one that passes a truth test
(iterator). The function returns as soon as it finds an acceptable
element, and doesn't traverse the entire list.
And if I understand correctly your condition, it could look like
MyCollection.find(function(model) {
return _.findWhere(model.get('Group'), {id: 34});
})
you can choose to use jQuery .find() . see examples here: http://api.jquery.com/find/
I need to filter entities based on one of their ListProperties having a certain element present. So kind of like:
entities.filter('listProp IN ',element) except where listProp and element are reversed if you see what I mean.
Anyone know how to filter like this?
If I understand you correctly, you want to find all entities which have that particular element present. You should be able to use: entities.filter('listProp =', element)
Look at: http://code.google.com/appengine/docs/python/datastore/typesandpropertyclasses.html#ListProperty
It says, "list_property = value tests if the value appears anywhere in the list".
Ok so it turns out the IN equality clause takes care of this case for lists automatically.
As in it does a for ... each on the list of elements to be searched for and if any one of them is present in the ListProperty for each entity it will return that entity.