Get JavaScript object from array of objects by value of property [duplicate]
Asked Answered
T

17

1317

Let's say I have an array of four objects:

var jsObjects = [
   {a: 1, b: 2}, 
   {a: 3, b: 4}, 
   {a: 5, b: 6}, 
   {a: 7, b: 8}
];

Is there a way that I can get the third object ({a: 5, b: 6}) by the value of the property b for example without a for...in loop?

Tman answered 20/12, 2012 at 1:57 Comment(4)
Yes, it is possible, as long as the value of b is unique among all of the objects in your array (which it is in this example)Viddah
@undefined Pretty sure op wants to search the array for at the object having b = 6Arizona
Related: Find an object by property value in an array of JavaScript objectsOnionskin
I like short & sweet and compatible with pre-ES6 browsers... jsObjects.find(function(x) {if(x.b == 6) return x}) You can use it to grab the property a at the same time... jsObjects.find(function(x) {if(x.b == 6) return x}).aGeraldine
W
1818

Filter array of objects, which property matches value, returns array:

var result = jsObjects.filter(obj => {
  return obj.b === 6
})

See the MDN Docs on Array.prototype.filter()

const jsObjects = [
  {a: 1, b: 2}, 
  {a: 3, b: 4}, 
  {a: 5, b: 6}, 
  {a: 7, b: 8}
]

let result = jsObjects.filter(obj => {
  return obj.b === 6
})

console.log(result)

Find the value of the first element/object in the array, otherwise undefined is returned.

var result = jsObjects.find(obj => {
  return obj.b === 6
})

See the MDN Docs on Array.prototype.find()

const jsObjects = [
  {a: 1, b: 2}, 
  {a: 3, b: 4}, 
  {a: 5, b: 6}, 
  {a: 7, b: 8}
]

let result = jsObjects.find(obj => {
  return obj.b === 6
})

console.log(result)
Wickiup answered 20/12, 2012 at 2:1 Comment(19)
This will return an arrayHalve
@nickf. I think it should, what if there are more objects with same properties? Otherwise: result[0] will be the first (unique) object in this case.Wickiup
Yeah, I guess it depends on what's needed. If it is just one item, I think filter isn't a great option, since it will firstly create a new unneeded object, and secondly it will continue through the entire array even when the object is found.Halve
It's worth mentioning that filter is only supported in modern browsers (i.e. IE9 and above) as it's part of ES5. So if you want to support older browsers you might want to fall back on one of the other methods suggested.Josselyn
To have it return just the first is easy. Add "[0]" to the end. #javaScriptIsAwesome! var result = jsObjects.filter(function( obj ) { return obj.b == 6; })[0];Marston
The question is "get JavaScript object", not "array of objects".Onionskin
@Gothdo is right. To get object we can use Array.find: var result = jsObjects.find(function( obj ) { return obj.b === 6; });Eugine
if I change something in a result object, will it be also changed in the jsObjects array?Jiva
Using the exact number 6 isn't useful for me. How do you pass in a variable?Odle
@Odle - if you have var x = 6; above var result, just replace the hard-coded 6 in the function with your variable (x).Lindon
also there is a tiny utility for this called super-arrayClan
We should actually be using find: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… It functions the same as filter but returns the first matching object, not an array.Zicarelli
@Zicarelli find() is an option, but it's not a "should" thing as every development house is different and not all are standardized on ES6 (especially in big companies where change is slow). If someone wants to return the first found object using filter(), then they just have to tack [0] to the end.Fluidextract
@Fluidextract Yeah sure I hear you.Zicarelli
@Wickiup is the element of result shallow copy of elements of jsObjects or deep copy?Eure
How could find the value in both a and b values?Effulgent
Also... when using a var... use == instead of ===Decerebrate
this answer broke my form. return val should be json; filter returns an arraySkuld
@Skuld - technically, you broke your form when you thought this answer was what you needed. The answer is solid for at least 1500 other people.Micamicaela
S
485
jsObjects.find(x => x.b === 6)

From MDN:

The find() method returns a value in the array, if an element in the array satisfies the provided testing function. Otherwise undefined is returned.


Side note: methods like find() and arrow functions are not supported by older browsers (like IE), so if you want to support these browsers, you should transpile your code using Babel.

Stoppage answered 14/2, 2016 at 20:51 Comment(7)
Note that this is not supported in IEConciliator
@Conciliator Yes, I wrote that "methods like find() and arrow functions are not supported by all browsers".Onionskin
This is the best option if you want to modify the object in the original array. filter() returns a copy of the object, not the original object, so changes will not be reflected in the original arrayPack
This is not exactly equivalent to @elclanrs's answer using filter(): it returns only the first match.Fluidextract
@Fluidextract The OP asked for "the object", not "an array of matching objects". elclanrs's answer is wrong.Onionskin
This example uses ECMAScript 6 arrow function. In case of errors when using arrow functions, there are other ways out. See (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…) and (dmitripavlutin.com/…)Mahon
Upvoted because it's not supported by IE. It's time to move on and I'm using it for that very reason.Mittiemittimus
B
199

I don't know why you are against a for loop (presumably you meant a for loop, not specifically for..in), they are fast and easy to read. Anyhow, here's some options.

For loop:

function getByValue(arr, value) {

  for (var i=0, iLen=arr.length; i<iLen; i++) {

    if (arr[i].b == value) return arr[i];
  }
}

.filter

function getByValue2(arr, value) {

  var result  = arr.filter(function(o){return o.b == value;} );

  return result? result[0] : null; // or undefined

}

.forEach

function getByValue3(arr, value) {

  var result = [];

  arr.forEach(function(o){if (o.b == value) result.push(o);} );

  return result? result[0] : null; // or undefined

}

If, on the other hand you really did mean for..in and want to find an object with any property with a value of 6, then you must use for..in unless you pass the names to check.

Example

function getByValue4(arr, value) {
  var o;

  for (var i=0, iLen=arr.length; i<iLen; i++) {
    o = arr[i];

    for (var p in o) {
      if (o.hasOwnProperty(p) && o[p] == value) {
        return o;
      }
    }
  }
}
Buine answered 20/12, 2012 at 2:58 Comment(7)
which one is the fastest one?Expeller
Foor loop by far the fastest method (jsperf.com/extract-props/1).Furness
with es6 and later use: for(let value of arr)Accordingly
@Buine any specific reason to store arr.length in iLen instead of directly using arr.length in the for condition as i<arr.length?Kuvasz
@VikasPrasad—just a minor performance enhancement, probably doesn't help now but in the early days it did.Buine
Brillent SollutionTenterhook
I often think filter() is the safer method because it assumes more than one result.Implacable
L
80

Ways to achieve the requirement :

  1. Using Array.find() method :

const jsObject = [
   {a: 1, b: 2}, 
   {a: 3, b: 4}, 
   {a: 5, b: 6}, 
   {a: 7, b: 8}
];

const filteredResult = jsObject.find((e) => e.b == 6);

console.log(filteredResult);
  1. Using Array.filter() method :

const jsObjects = [
   {a: 1, b: 2}, 
   {a: 3, b: 4}, 
   {a: 5, b: 6}, 
   {a: 7, b: 8}
];

const filterObj = jsObjects.filter((e) => e.b == 6);

console.log(filterObj[0]);
  1. Using for...in loop :

const jsObjects = [
   {a: 1, b: 2}, 
   {a: 3, b: 4}, 
   {a: 5, b: 6}, 
   {a: 7, b: 8}
];

for (const i in jsObjects) {
  if (jsObjects[i].b == 6) {
    console.log(jsObjects[i]);
  }
}
Lennie answered 2/11, 2016 at 9:57 Comment(0)
R
34

OK, there are few ways to do that, but let's start with the simplest one and latest approach to do this, this function is called find().

Just be careful when you using find to as even IE11 dosn't support it, so it needs to be transpiled...

so you have this object as you said:

var jsObjects = [
   {a: 1, b: 2}, 
   {a: 3, b: 4}, 
   {a: 5, b: 6}, 
   {a: 7, b: 8}
];

and you can write a function and get it like this:

function filterValue(obj, key, value) {
  return obj.find(function(v){ return v[key] === value});
}

and use the function like this:

filterValue(jsObjects, "b", 6); //{a: 5, b: 6}

Also in ES6 for even shortened version:

const filterValue = (obj, key, value)=> obj.find(v => v[key] === value);

This method only return the first value which match..., for better result and browser support, you can use filter:

const filterValue = (obj, key, value)=> obj.filter(v => v[key] === value);

and we will return [{a: 5, b: 6}]...

This method will return an array instead...

You simpley use for loop as well, create a function like this:

function filteredArray(arr, key, value) {
  const newArray = [];
  for(i=0, l=arr.length; i<l; i++) {
    if(arr[i][key] === value) {
      newArray.push(arr[i]);
    }
  }
 return newArray;
}

and call it like this:

filteredArray(jsObjects, "b", 6); //[{a: 5, b: 6}]
Risner answered 30/3, 2018 at 5:38 Comment(1)
Thanks @Alireza. Very complete answer. As for the .filter part: < This method will return an array instead... Not the most elegant solution, but consider adding [0] at the end, for a quick fix. const filterValue = (obj, key, value)=> obj.filter(v => v[key] === value)[0];Pier
M
31

See this documentation Array.prototype.find()

Example:

var inventory = [
    {name: 'apples', quantity: 2},
    {name: 'bananas', quantity: 0},
    {name: 'cherries', quantity: 5}
];

function findCherries(fruit) { 
    return fruit.name === 'cherries';
}

console.log(inventory.find(findCherries)); 
// { name: 'cherries', quantity: 5 }
Meingolda answered 7/9, 2017 at 11:35 Comment(4)
Not clear how this works with the 'find()' method you're calling. Additionally Object.values() is not supported in Internet Explorer.Giblet
It seems that the link is mistaken. The author probably intended this one: Array.prototype.find()Pier
What does this return if it doesn't find anything? undefined?Thorax
@OliverDixon yes.Meingolda
P
23

Using underscore.js:

var foundObject = _.findWhere(jsObjects, {b: 6});
Paratyphoid answered 16/10, 2015 at 18:15 Comment(1)
E
21

It looks like in the ECMAScript 6 proposal there are the Array methods find() and findIndex(). MDN also offers polyfills which you can include to get the functionality of these across all browsers.

find():

function isPrime(element, index, array) {
    var start = 2;
    while (start <= Math.sqrt(element)) {
        if (element % start++ < 1) return false;
    }
    return (element > 1);
}

console.log( [4, 6, 8, 12].find(isPrime) ); // undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5

findIndex():

function isPrime(element, index, array) {
    var start = 2;
    while (start <= Math.sqrt(element)) {
        if (element % start++ < 1) return false;
    }
    return (element > 1);
}

console.log( [4, 6, 8, 12].findIndex(isPrime) ); // -1, not found
console.log( [4, 6, 7, 12].findIndex(isPrime) ); // 2
Equate answered 4/4, 2014 at 7:39 Comment(0)
E
19

If you are looking for a single result, rather than an array, may I suggest reduce?

Here is a solution in plain 'ole javascript that returns a matching object if one exists, or null if not.

var result = arr.reduce(function(prev, curr) { return (curr.b === 6) ? curr : prev; }, null);
Encaustic answered 8/12, 2015 at 17:10 Comment(0)
H
18

If I understand correctly, you want to find the object in the array whose b property is 6?

var found;
jsObjects.some(function (obj) {
  if (obj.b === 6) {
    found = obj;
    return true;
  }
});

Or if you were using underscore:

var found = _.select(jsObjects, function (obj) {
  return obj.b === 6;
});
Halve answered 20/12, 2012 at 2:3 Comment(4)
some just returns true or false, it doesn't return the matching object.Buine
@Buine yep, well aware. Note how I'm not assigning the value from it? :) It's just being used here as a way to short-circuit the loop.Halve
Overcomplicated. .some() is meant to determine whether some element in the array passes the test. In this case it would be better to use .forEach(), since you already decided to assign the result to a variable.Onionskin
@Gothdo why would you continue looping through the array when you already have the result? The return true in a .some is essentially like a break in a for loop.Halve
J
14

You can use it with the arrow function as well like as below :

var demoArray = [
   {name: 'apples', quantity: 2},
   {name: 'bananas', quantity: 0},
   {name: 'cherries', quantity: 5}
];

var result = demoArray.filter( obj => obj.name === 'apples')[0];
console.log(result);
// {name: 'apples', quantity: 2}
Jaxartes answered 16/1, 2018 at 8:7 Comment(0)
Y
11

How about using _.find(collection, [predicate=_.identity], [fromIndex=0]) of lo-dash to get object from array of objects by object property value. You could do something like this:

var o = _.find(jsObjects, {'b': 6});

Arguments:

collection (Array|Object): The collection to inspect.
[predicate=_.identity] (Function): The function invoked per iteration.
[fromIndex=0] (number): The index to search from.

Returns

(*): Returns the matched element (in your case, {a: 5, b: 6}), else undefined.

In terms of performance, _.find() is faster as it only pulls the first object with property {'b': 6}, on the other hand, if suppose your array contains multiple objects with matching set of properties (key:value), then you should consider using _.filter() method. So in your case, as your array has a single object with this property, I would use _.find().

Yazzie answered 4/12, 2016 at 11:37 Comment(0)
I
8

Made the best/fastest part of this answer more re-usable & clear:

function getElByPropVal(myArray, prop, val){
    for (var i = 0, length = myArray.length; i < length; i++) {
        if (myArray[i][prop] == val){
            return myArray[i];
        }
    }
}
Interdependent answered 15/2, 2018 at 19:31 Comment(0)
K
6
var result = jsObjects.filter(x=> x.b === 6);

will be better, using return in filter sometimes you can't get result (I dunno why)

Kiger answered 9/2, 2018 at 8:18 Comment(0)
E
3

To get first object from array of objects by a specific property value:

function getObjectFromObjectsArrayByPropertyValue(objectsArray, propertyName, propertyValue) {
  return objectsArray.find(function (objectsArrayElement) {
    return objectsArrayElement[propertyName] == propertyValue;
  });
}

function findObject () {
  var arrayOfObjectsString = document.getElementById("arrayOfObjects").value,
      arrayOfObjects,
      propertyName = document.getElementById("propertyName").value,
      propertyValue = document.getElementById("propertyValue").value,
      preview = document.getElementById("preview"),
      searchingObject;
  
  arrayOfObjects = JSON.parse(arrayOfObjectsString);
  
  console.debug(arrayOfObjects);
  
  if(arrayOfObjects && propertyName && propertyValue) {
    searchingObject = getObjectFromObjectsArrayByPropertyValue(arrayOfObjects, propertyName, propertyValue);
    if(searchingObject) {
      preview.innerHTML = JSON.stringify(searchingObject, false, 2);
    } else {
      preview.innerHTML = "there is no object with property " + propertyName + " = " + propertyValue + " in your array of objects";
    }
  }
}
pre {
  padding: 5px;
  border-radius: 4px;
  background: #f3f2f2;
}

textarea, button {
  width: 100%
}
<fieldset>
  <legend>Input Data:</legend>
  <label>Put here your array of objects</label>
  <textarea rows="7" id="arrayOfObjects">
  [
    {"a": 1, "b": 2},
    {"a": 3, "b": 4},
    {"a": 5, "b": 6},
    {"a": 7, "b": 8, "c": 157}
  ]
  </textarea>

  <hr>

  <label>property name: </label> <input type="text" id="propertyName"  value="b"/>
  <label>property value: </label> <input type="text" id="propertyValue" value=6 />
     
</fieldset>
<hr>
<button onclick="findObject()">find object in array!</button>
<hr>
<fieldset>
  <legend>Searching Result:</legend>
  <pre id="preview">click find</pre>
</fieldset>
Eugine answered 27/4, 2016 at 10:8 Comment(0)
L
2

Using find with bind to pass specific key values to a callback function.

   function byValue(o) { 
       return o.a === this.a && o.b === this.b; 
   };   

   var result = jsObjects.find(byValue.bind({ a: 5, b: 6 }));
Lightfoot answered 10/4, 2017 at 12:26 Comment(0)
U
-31
var jsObjects = [{a: 1, b: 2}, {a: 3, b: 4}, {a: 5, b: 6}, {a: 7, b: 8}];

to access the third object, use: jsObjects[2];
to access the third object b value, use: jsObjects[2].b;

Unconditioned answered 23/7, 2015 at 4:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.