648

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.

dreftymac
  • 31,404
  • 26
  • 119
  • 182
Arlen Beiler
  • 15,336
  • 34
  • 92
  • 135

20 Answers20

1366

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);
Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
  • For your second example, you should take `arr` in as the third argument to the callback function. That's what it's meant for. – Aadit M Shah Aug 20 '17 at 02:34
  • @AaditMShah I wonder what the point of that is. The `arr` variable is already available in the outer scope. – Šime Vidas Aug 20 '17 at 02:42
  • 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. – Aadit M Shah Aug 20 '17 at 02:45
  • 1
    @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. – Šime Vidas Aug 20 '17 at 04:23
  • 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. =) – Aadit M Shah Aug 20 '17 at 08:26
  • Given the Aug '17 update, this is the best answer. Javascript's find() stops on the first match: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find – mojave Jul 04 '18 at 15:57
  • 1
    @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. – Šime Vidas Aug 03 '18 at 17:50
  • It is not obvious, but for future Googlers, find was implemented in the 2015 spec. Shows a syntax error in VS2013. The link @mojave added has more information about ECMA-262 which added this version of find. – John White Aug 06 '18 at 13:37
  • What if i just want the value like just `string 1` instead of returning the whole filtered array ? – Kopi Bryant Mar 10 '21 at 06:08
  • Nice, very helpful – Ubaid Ullah Feb 01 '22 at 09:46
  • Damnnnnn you're too good. itworked – Agent K Apr 26 '22 at 02:33
  • @KopiBryant there is the dot notation which is used in the answer already. You can go on from there. – Timo Oct 17 '22 at 11:45
321

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)
Christian
  • 332
  • 1
  • 7
  • 19
Asciiom
  • 9,867
  • 7
  • 38
  • 57
220

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++);
rujmah
  • 2,267
  • 1
  • 15
  • 13
  • 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... http://stackoverflow.com/questions/35986017/can-you-use-array-filter-in-an-angular-binding – Tim Holt Dec 08 '16 at 22:55
  • 5
    If it is just one value, here, you can also shorthand it to: array.find(x => x.name === "string 1").name = "some new string"; – Keegan G Apr 25 '17 at 19:30
  • 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 below – Christian Matthew Jul 27 '17 at 16:01
  • 10
    There is already [findIndex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) method available that returns the index instead of the object which saves you from using `indexOf` again. – Vishnu Y S Apr 19 '18 at 06:16
  • I was only able to make this work using ==, not === – xxxRxxx Apr 09 '21 at 04:51
85

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

array[array.findIndex(x => x.name == 'string 1')]
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
p.pradnya
  • 1,039
  • 1
  • 9
  • 9
  • 5
    findIndex is the right solution. certainly not foreach inside foreach. this should be accepted answer – ononononon Jul 28 '17 at 13:28
  • This solution works well and is concise and clean! – Jordan Jan 22 '20 at 16:24
  • 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. – VLAZ Apr 20 '21 at 11:46
83

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');
}
Gaurav Sharma
  • 1,983
  • 18
  • 18
  • const serached = search("string 1"); if (serached) { console.log(serached.name, serached.value, serached.other); } else { console.log('No result found'); } – user3768564 Oct 17 '21 at 00:20
  • 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'); } – user3768564 Oct 17 '21 at 00:23
  • @martti Thanks for pointing that out. Edited the anaswer – Gaurav Sharma Mar 25 '22 at 11:58
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);
Zahirul Haque
  • 1,599
  • 17
  • 22
  • 10
    'find' is a better option than 'filter' to find a specific object – Ashikur Rahman Nov 14 '19 at 11:26
  • 3
    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't – Someone Special Sep 04 '20 at 11:34
  • 11
    The problem with filter is that it returns an array, not the value! – rimkashox Nov 24 '20 at 11:18
  • I was looking for this kind of answer instead of the top ones. tnx :) – Farhad Mar 03 '21 at 10:06
  • 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. – msanjay Aug 08 '21 at 16:06
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);
MarvinVK
  • 2,964
  • 1
  • 22
  • 21
  • 3
    you can't return from foreach loop, it will iterate for all items, irrespective of any condition you put. – test_124 Aug 08 '18 at 15:26
  • @ShashankGaurav Your right I was using my example in a function. So I updated my answer. Thnx for the feedback! – MarvinVK Nov 19 '18 at 12:44
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];
João Silva
  • 89,303
  • 29
  • 152
  • 158
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

Wallace Vizerra
  • 3,382
  • 2
  • 28
  • 29
  • 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'}));` – James Oct 25 '17 at 23:36
  • @James 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. – Autumn Leonard Jul 27 '18 at 15:24
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]);
Durgpal Singh
  • 11,481
  • 4
  • 37
  • 49
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');

Community
  • 1
  • 1
Simon Dragsbæk
  • 2,367
  • 3
  • 30
  • 53
  • 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 (http://stackoverflow.com/questions/3010840/loop-through-array-in-javascript?rq=1) – silverlight513 May 12 '16 at 07:49
  • Worked great for me so far, but it might be an anti pattern – Simon Dragsbæk May 12 '16 at 08:40
  • It does work but yeah it's an anti-pattern and bad practice – silverlight513 May 12 '16 at 09:21
  • 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 before – Simon Dragsbæk May 12 '16 at 09:36
  • @silverlight513 if you have improvements to the new solution please state them for the communities sake – Simon Dragsbæk May 12 '16 at 09:46
  • 1
    @silverlight513 also added mocha tests and results – Simon Dragsbæk May 12 '16 at 10:30
  • 1
    +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). – silverlight513 May 12 '16 at 15:14
  • @Simon https://stackoverflow.com/questions/44550439/javascript-search-array-of-nested-objects-and-return-parent-if-value-is-found – Valay Jun 14 '17 at 21:29
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;
    }
}
VisioN
  • 143,310
  • 32
  • 282
  • 281
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'};
Keegan G
  • 176
  • 4
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'}
);
narendra-choudhary
  • 4,582
  • 4
  • 38
  • 58
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");
cse031sust02
  • 109
  • 1
  • 7
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

Ratheesh
  • 631
  • 8
  • 8
  • this works fine. how do I make it work for nested object ? – Valay Jun 14 '17 at 12:02
  • https://stackoverflow.com/questions/44550439/javascript-search-array-of-nested-objects-and-return-parent-if-value-is-found – Valay Jun 14 '17 at 21:28
0

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

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

sucil
  • 116
  • 2
  • 7
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);
George Eracleous
  • 4,278
  • 6
  • 41
  • 50
-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;
            }
        }

    }
}
-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;

Christian Matthew
  • 4,014
  • 4
  • 33
  • 43