Find a value in an array of objects in Javascript [duplicate]
Asked Answered
C

20

659

I know similar questions have been asked before, but this one is a little different. I have an array of unnamed objects, which contain an array of named objects, and I need to get the object where "name" is "string 1". Here is an example array.

var array = [
    { name:"string 1", value:"this", other: "that" },
    { name:"string 2", value:"this", other: "that" }
];

Update: I should have said this earlier, but once I find it, I want to replace it with an edited object.

Cq answered 17/9, 2012 at 15:19 Comment(1)
If you know where it is, you can just use array[0]['name']Sedimentology
G
324

You can loop over the array and test for that property:

function search(nameKey, myArray){
    for (let i=0; i < myArray.length; i++) {
        if (myArray[i].name === nameKey) {
            return myArray[i];
        }
    }
}

const array = [
    { name:"string 1", value:"this", other: "that" },
    { name:"string 2", value:"this", other: "that" }
];

const resultObject = search("string 1", array);
console.log(resultObject)
Grados answered 17/9, 2012 at 15:23 Comment(3)
change the function to this search(nameKey, prop, myArray) and the if clause to this if (myArray[i][prop]=== nameKey) { and you search for any properties inside the objectImplacental
also there is a tiny utility for this called super-arrayAlkane
in case of integer value, use ==Mealy
S
1389

Finding the array element:

let arr = [
    { name:"string 1", value:"this", other: "that" },
    { name:"string 2", value:"this", other: "that" }
];

let obj = arr.find(o => o.name === 'string 1');

console.log(obj);

Replacing the array element:

let arr = [
    { name:"string 1", value:"this", other: "that" },
    { name:"string 2", value:"this", other: "that" }
];

let obj = arr.find((o, i) => {
    if (o.name === 'string 1') {
        arr[i] = { name: 'new string', value: 'this', other: 'that' };
        return true; // stop searching
    }
});

console.log(arr);
Satsuma answered 17/9, 2012 at 15:24 Comment(12)
For your second example, you should take arr in as the third argument to the callback function. That's what it's meant for.Tyrant
@AaditMShah I wonder what the point of that is. The arr variable is already available in the outer scope.Inofficious
Two reasons. First, it might not always be the case the the arr variable is available in the outer scope. Second, it's faster because it's a local variable.Tyrant
@AaditMShah If there is no variable, then yes, that third argument can be useful. But since we have the variable in this case, there is no need for it. Regarding the second point, it’s not faster in practice. That 1-microsecond improvement isn’t even worth talking about, let alone creating code for it, IMHO.Inofficious
Well, the code is just five extra characters (i.e. , arr). That being said, I see your point. I guess it's just a matter of preference. My OCD won't allow me to use a non-local variable when the array is anyways going to be passed as an argument to the callback. =)Tyrant
Given the Aug '17 update, this is the best answer. Javascript's find() stops on the first match: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Noreen
@nishant No need. The find method invokes the function for every array element automatically, until a truthy value is returned. So if the function doesn’t return anything, the return value is undefined, which is not truthy, so the function is invoked for the next element normally.Inofficious
It is not obvious, but for future Googlers, find was implemented in the 2015 spec. Shows a syntax error in VS2013. The link @Noreen added has more information about ECMA-262 which added this version of find.Affrica
What if i just want the value like just string 1 instead of returning the whole filtered array ?Tigre
Nice, very helpfulEquivalency
Damnnnnn you're too good. itworkedShortbread
@KopiBryant there is the dot notation which is used in the answer already. You can go on from there.Flimsy
G
324

You can loop over the array and test for that property:

function search(nameKey, myArray){
    for (let i=0; i < myArray.length; i++) {
        if (myArray[i].name === nameKey) {
            return myArray[i];
        }
    }
}

const array = [
    { name:"string 1", value:"this", other: "that" },
    { name:"string 2", value:"this", other: "that" }
];

const resultObject = search("string 1", array);
console.log(resultObject)
Grados answered 17/9, 2012 at 15:23 Comment(3)
change the function to this search(nameKey, prop, myArray) and the if clause to this if (myArray[i][prop]=== nameKey) { and you search for any properties inside the objectImplacental
also there is a tiny utility for this called super-arrayAlkane
in case of integer value, use ==Mealy
G
223

In ES6 you can use Array.prototype.find(predicate, thisArg?) like so:

array.find(x => x.name === 'string 1')

http://exploringjs.com/es6/ch_arrays.html#_searching-for-array-elements https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/find

To then replace said object (and use another cool ES6 method fill) you could do something like:

let obj = array.find(x => x.name === 'string 1');
let index = array.indexOf(obj);
array.fill(obj.name='some new string', index, index++);
Galingale answered 21/7, 2016 at 9:34 Comment(5)
I happened to find this answer when searching for how to use find in an Angular2 template to set an attribute. It ends up this post has a good combination of ES6 find with pipes... #35986517Suppletory
If it is just one value, here, you can also shorthand it to: array.find(x => x.name === "string 1").name = "some new string";Chic
thank you si.!!!! was able to use this code to literally find something in the array and then get it out the name and use the variable... I will post my answer belowNuzzi
There is already findIndex method available that returns the index instead of the object which saves you from using indexOf again.Elver
I was only able to make this work using ==, not ===Splenomegaly
F
86

As per ECMAScript 6, you can use the findIndex function.

array[array.findIndex(x => x.name == 'string 1')]
Frymire answered 18/5, 2017 at 12:56 Comment(3)
findIndex is the right solution. certainly not foreach inside foreach. this should be accepted answerLeporid
This solution works well and is concise and clean!Tarnetgaronne
With ES6 you'd have .find() which directly returns the element. Fetching the index with .findIndex() and then fetching the element by the index is not needed.Brockway
T
85

Considering you have following snippet:

var array = [
    { name:"string 1", value:"this", other: "that" },
    { name:"string 2", value:"this", other: "that" }
];

You can use the following function to search for items

const search = what => array.find(element => element.name === what);

And you can check whether the item was found or not.

const found = search("string1");
if (found) {
    console.log(found.value, found.other);
} else {
    console.log('No result found');
}
Talkfest answered 10/2, 2018 at 8:52 Comment(3)
const serached = search("string 1"); if (serached) { console.log(serached.name, serached.value, serached.other); } else { console.log('No result found'); }Unborn
Even BETTER solution: const search = (what, arr) => arr.find(element => element[what.split(':')[0]] === what.split(':')[1]); const serached = search("value:string 1",array); if (serached) { console.log(serached.name, serached.value, serached.other); } else { console.log('No result found'); }Unborn
@martti Thanks for pointing that out. Edited the anaswerTalkfest
C
70
var array = [
    { name:"string 1", value:"this", other: "that" },
    { name:"string 2", value:"this", other: "that" }
];

var foundValue = array.filter(obj=>obj.name==='string 1');

console.log(foundValue);
Clinometer answered 13/12, 2017 at 10:30 Comment(5)
'find' is a better option than 'filter' to find a specific objectPyoid
why is find a better option, and able to help find specific object?? The difference is it gets the first object vs returning all results. find doesn't tell u how many result matches the string. on the contrary filter supports IE and find doesn'tGlomeration
The problem with filter is that it returns an array, not the value!Esther
I was looking for this kind of answer instead of the top ones. tnx :)Sisyphean
The find() method returns the first value that matches from the collection. Once it matches the value in findings, it will not check the remaining values in the array collection. The filter() method returns the matched values in an array from the collection.Latonya
F
27

With a foreach:

let itemYouWant = null;
array.forEach((item) => {
    if (item.name === 'string 1') {
        itemYouWant = item;
    }
});
console.log(itemYouWant);

Or even better with a map:

const itemYouWant = array.map((item) => {
    if (item.name === 'string 1') {
        return item;
    }
    return null;
});
console.log(itemYouWant);
Frumpish answered 4/5, 2017 at 9:19 Comment(2)
you can't return from foreach loop, it will iterate for all items, irrespective of any condition you put.Burkhard
@ShashankGaurav Your right I was using my example in a function. So I updated my answer. Thnx for the feedback!Frumpish
F
24

Either use a simple for-loop:

var result = null;
for (var i = 0; i < array.length; i++) { 
  if (array[i].name === "string 1") { 
    result = array[i];
    break;
  } 
}

Or if you can, that is, if your browser supports it, use Array.filter, which is much more terse:

var result = array.filter(function (obj) {
  return obj.name === "string 1";
})[0];
Factfinding answered 17/9, 2012 at 15:24 Comment(3)
When the obj is returned, how do I get its position in the original array?Haiphong
@VedranMaricevic. Using array.fill()Pandorapandour
When no ES6 support (such as using Google Tag Manager), for loops solve the problem. :)Stupidity
G
22

with underscore.js use the findWhere method:

var array = [
    { name:"string 1", value:"this", other: "that" },
    { name:"string 2", value:"this", other: "that" }
];


var result = _.findWhere(array, {name: 'string 1'});

console.log(result.name);

See this in JSFIDDLE

Gardel answered 31/7, 2015 at 14:16 Comment(2)
If you need to know the array index (not just the matching object) you can mix _.findWhere() with _.indexOf() like so: var index = _.indexOf(array, _.findWhere(array, {name: 'string 1'}));Kofu
@Kofu Seems like a waste, as that will have to iterate through the array twice. Plus, you're not gaining any code clarity from underscore at that point. Better to just write your own well-names function if you're resorting to that.Slavonic
B
20

One line answer. You can use filter function to get result.

var array = [
    { name:"string 1", value:"this", other: "that" },
    { name:"string 2", value:"this", other: "that" }
];

console.log(array.filter(function(arr){return arr.name == 'string 1'})[0]);
Bhutan answered 9/11, 2017 at 4:43 Comment(0)
U
15

New answer

I added the prop as a parameter, to make it more general and reusable

/**
 * Represents a search trough an array.
 * @function search
 * @param {Array} array - The array you wanna search trough
 * @param {string} key - The key to search for
 * @param {string} [prop] - The property name to find it in
 */

function search(array, key, prop){
    // Optional, but fallback to key['name'] if not selected
    prop = (typeof prop === 'undefined') ? 'name' : prop;    

    for (var i=0; i < array.length; i++) {
        if (array[i][prop] === key) {
            return array[i];
        }
    }
}

Usage:

var array = [
    { 
        name:'string 1', 
        value:'this', 
        other: 'that' 
    },
    { 
        name:'string 2', 
        value:'this', 
        other: 'that' 
    }
];

search(array, 'string 1');
// or for other cases where the prop isn't 'name'
// ex: prop name id
search(array, 'string 1', 'id');

Mocha test:

var assert = require('chai').assert;

describe('Search', function() {
    var testArray = [
        { 
            name: 'string 1', 
            value: 'this', 
            other: 'that' 
        },
        { 
            name: 'string 2', 
            value: 'new', 
            other: 'that' 
        }
    ];

    it('should return the object that match the search', function () {
        var name1 = search(testArray, 'string 1');
        var name2 = search(testArray, 'string 2');

        assert.equal(name1, testArray[0]);
        assert.equal(name2, testArray[1]);

        var value1 = search(testArray, 'this', 'value');
        var value2 = search(testArray, 'new', 'value');

        assert.equal(value1, testArray[0]);
        assert.equal(value2, testArray[1]);
    });

    it('should return undefined becuase non of the objects in the array have that value', function () {
        var findNonExistingObj = search(testArray, 'string 3');

        assert.equal(findNonExistingObj, undefined);
    });

    it('should return undefined becuase our array of objects dont have ids', function () {
        var findById = search(testArray, 'string 1', 'id');

        assert.equal(findById, undefined);
    });
});

test results:

Search
    ✓ should return the object that match the search
    ✓ should return undefined becuase non of the objects in the array have that value
    ✓ should return undefined becuase our array of objects dont have ids


  3 passing (12ms)

Old answer - removed due to bad practices

if you wanna know more why it's bad practice then see this article:

Why is extending native objects a bad practice?

Prototype version of doing an array search:

Array.prototype.search = function(key, prop){
    for (var i=0; i < this.length; i++) {
        if (this[i][prop] === key) {
            return this[i];
        }
    }
}

Usage:

var array = [
    { name:'string 1', value:'this', other: 'that' },
    { name:'string 2', value:'this', other: 'that' }
];

array.search('string 1', 'name');

Unshackle answered 13/10, 2015 at 8:5 Comment(8)
You should never modify the prototype of a native object. Have a google around for why this is bad, there's plenty of articles and stackoverflow questions. The answer in this question gives a good reason (#3011340)Payson
Worked great for me so far, but it might be an anti patternApathy
It does work but yeah it's an anti-pattern and bad practicePayson
I see your point after reading up on this my self it's really bad for the life cycle of a web application. Thanks for pointing that out, havn't noticed that beforeApathy
@Payson if you have improvements to the new solution please state them for the communities sakeApathy
@Payson also added mocha tests and resultsApathy
+1 for adding tests, they're always something worth adding. I'd have to say though that Šime Vidas's use of filter seems to be a much cleaner way of looping through an array to find an object (imo).Payson
@Simon #44550939Sinistrous
E
10

You can do it with a simple loop:

var obj = null;    
for (var i = 0; i < array.length; i++) {
    if (array[i].name == "string 1") {
        obj = array[i];
        break;
    }
}
Estrada answered 17/9, 2012 at 15:21 Comment(4)
What is the empty object good for?Contraction
@Contraction It depends on what is the purpose of the code. How about null then?Estrada
Makes more sense to me, thanks. Just undefined would be Ok as well imho…Contraction
@Contraction Maybe null is more depictive for not found element.Estrada
C
4

Another way (to aid @NullUserException and @Wexoni's comments) is to retrieve the object's index in the array and then go from there:

var index = array.map(function(obj){ return obj.name; }).indexOf('name-I-am-looking-for');
// Then we can access it to do whatever we want
array[index] = {name: 'newName', value: 'that', other: 'rocks'};
Chic answered 9/6, 2016 at 20:53 Comment(0)
M
3

Similar to previous answers I used the following:

    Array.prototype.getIemtByParam = function(paramPair) {
      var key = Object.keys(paramPair)[0];
      return this.find(function(item){return ((item[key] == paramPair[key]) ? true: false)});
    }

usage:

myArray.getIemtByParam(
    {name: 'Sasha'}
);
Mideast answered 20/11, 2015 at 11:35 Comment(0)
D
2

Here is the solution for search and replace

function searchAndUpdate(name,replace){
    var obj = array.filter(function ( obj ) {
        return obj.name === name;
    })[0];
    obj.name = replace;
}

searchAndUpdate("string 2","New String 2");
Detest answered 17/6, 2014 at 12:5 Comment(0)
H
2

Are you looking for generic Search(Filter) across the item in the object list without specifying the item key

Input

var productList = [{category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'}, {category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'}, {category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'}, {category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'}, {category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'}, {category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}]
function customFilter(objList, text){
if(undefined === text || text === '' ) return objList;
return objList.filter(product => {
    let flag;
    for(let prop in product){
        flag = false;
        flag = product[prop].toString().indexOf(text) > -1;
        if(flag)
        break;
    }
return flag;
});}

Execute

customFilter(productList, '$9');

enter image description here

Hilel answered 19/3, 2017 at 19:56 Comment(2)
this works fine. how do I make it work for nested object ?Sinistrous
#44550939Sinistrous
G
0

if you are using jQuery try $.grep().

http://api.jquery.com/jquery.grep/

Gleesome answered 27/5, 2016 at 18:16 Comment(0)
C
0

You can use query-objects from npm. You can search an array of objects using filters.

const queryable = require('query-objects');

const users = [
    {
      firstName: 'George',
      lastName: 'Eracleous',
      age: 28
    },
    {
      firstName: 'Erica',
      lastName: 'Archer',
      age: 50
    },
    {
      firstName: 'Leo',
      lastName: 'Andrews',
      age: 20
    }
];

const filters = [
    {
      field: 'age',
      value: 30,
      operator: 'lt'
    },
    {
      field: 'firstName',
      value: 'Erica',
      operator: 'equals'
    }
];

// Filter all users that are less than 30 years old AND their first name is Erica
const res = queryable(users).and(filters);

// Filter all users that are less than 30 years old OR their first name is Erica
const res = queryable(users).or(filters);
Castilian answered 5/8, 2016 at 9:41 Comment(0)
M
-1
function getValue(){
    for(var i = 0 ; i< array.length; i++){
        var obj = array[i];
        var arr = array["types"];
        for(var j = 0; j<arr.length;j++ ){
            if(arr[j] == "value"){
                return obj;
            }
        }

    }
}
Maziemazlack answered 12/12, 2014 at 12:7 Comment(0)
N
-1

This answer is good for typescript / Angular 2, 4, 5+

I got this answer with the help of @rujmah answer above. His answer brings in the array count... and then find's the value and replaces it with another value...

What this answer does is simply grabs the array name that might be set in another variable via another module / component... in this case the array I build had a css name of stay-dates. So what this does is extract that name and then allows me to set it to another variable and use it like so. In my case it was an html css class.

let obj = this.highlightDays.find(x => x.css); let index = this.highlightDays.indexOf(obj); console.log('here we see what hightlightdays is ', obj.css); let dayCss = obj.css;

Nuzzi answered 27/7, 2017 at 16:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.