Reputation: 1420
As the title says, I'm trying to get property of object after find, safely.
Let's assume, that I have such array:
var ppl = [
{ id: 1, name: 'Smith' },
{ id: 2, name: 'Wesson' },
{ id: 3, name: 'Remington' },
{ id: 4, name: 'Colt' }
];
So I'm trying to get a name of one of this respectful gentlemans by id, so I'm using _.find
.
var person = _.find(ppl, function(p) { return p.id === 2; });
I'm looking for a way to safely get name
in the _
chain. Something like:
var personName = _.chain(ppl)
.find(function(p) { return p.id === 2; })
.get('name') //<-- can't find appropriate method :(
.values();
Ofc I can do it with checks like if(person && person.name)... Or even write my own prototype method, but don't want to reinvent the wheel.
Upvotes: 1
Views: 2019
Reputation: 27976
As you're using get
I'm assuming that you're using lodash and not underscore. If so then you could use defaultTo which was introduced in version 4.14.0:
var ppl = [
{ id: 1, name: 'Smith' },
{ id: 2, name: 'Wesson' },
{ id: 3, name: 'Remington' },
{ id: 4, name: 'Colt' }
];
var nullPerson = {
id: 0,
name: 'null'
}
var personName = _.chain(ppl)
.find({id: 99})
.defaultTo(nullPerson)
.get('name')
.value();
console.log(personName);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Upvotes: 2
Reputation: 29004
I believe GruffBunny is correct in that you seem to be using Lodash, rather than Underscore. I also find like the solution provided in that answer to be quite elegant, but I wanted to show an alternative.
Note: I will provide an Underscore answer, since the question is tagged as such but also a Lodash one, since OP seems to be interested in that
One thing that I always found a bit awkward is the exact situation you're in - chain (an array) -> do operations -> find -> do other things. The Object functions in Underscore are slightly off. However, we can still try to do it:
var ppl = [
{ id: 1, name: 'Smith' },
{ id: 2, name: 'Wesson' },
{ id: 3, name: 'Remington' },
{ id: 4, name: 'Colt' }
];
function findName(id) {
return _.chain(ppl)
.findWhere({id: id}) // <- shorter syntax than _.find and does the same as supplying your own function.
// It's even shorter than the already short fat arrow syntax which would be: (p => p.id === 2)
.pick('name') // <- extract a new object that has a single property "name"
.map() //<- 1. for objects, it's equivalent to mapping the values only, e.g., _.map(_.values(obj))
//^- 2. if no argument is specified, it defaults to _.identity
.first() // <- since the previous step returns an array of one value this step unwraps it and leaves you with a plain value
.value(); // end chain, return result
}
console.log("Find ID = 2:", findName(2));
console.log("Find ID = 42:", findName(42));
console.log('Find ID = "2" (string value):', findName("2"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
So, this will do the job but it is a bit awkward. You're lacking the .get
, so you have to pluck -> map -> first to do the equivalent. It's not strictly bad_ but it's not-as-good as it could. One alternative is to keep your single result in an array which will allow you to run additional functions. So, you can do this
_.chain(ppl)
.where({id: id}) //it's basically "filterWhere" like _.findWhere but it returns all results in an array. In this case, it would be a single result purely so we can do the below
.map('name') //<- allows you to map by name of the property but only with arrays
.first() // <- still have to unwrap
.value();
let's see the equivalent
Lodash is a bit better, since it has a bit smoother syntax and also has a bit better handling of objects, so you don't face situations where you have to keep them in an array of one value.
var ppl = [
{ id: 1, name: 'Smith' },
{ id: 2, name: 'Wesson' },
{ id: 3, name: 'Remington' },
{ id: 4, name: 'Colt' }
];
function findName(id, defaultName) {
return _.chain(ppl)
.find({id: id}) //<- Lodash does not have _.findWhere but the normal _.find already handles this
.get('name') // <- see, much simpler! You can also supply a second argument which would be returned as a default value
.value();
}
console.log("Find ID = 2:", findName(2));
console.log("Find ID = 42:", findName(42));
console.log('Find ID = "2" (string value):', findName("2"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Upvotes: 2