20

I am trying to get all the keys and values of an object that begin with imageIds.

My object appears as the following:

{
    title: 'fsdfsd',
    titleZh: 'fsdfsd',
    body: 'fsdf',
    bodyZh: 'sdfsdf',
    imageIds: '/uploads/tmp/image-3.png',
    imageIdsZh: '' 
}

but I only need the properties imageIds, and imageIdsZh. However tomorrow, a object might contain imageIdsBlah and I would need to pick it up as well. I could remove the first few properties from the object, but then the next object might contain additional properties such as foo: 'bar'

Neil
  • 2,509
  • 7
  • 32
  • 47
  • Any thoughts? How about plain old `foreach` + `if`? – zerkms Dec 10 '13 at 03:08
  • possible duplicate of [How to list the properties of a JavaScript object](http://stackoverflow.com/questions/208016/how-to-list-the-properties-of-a-javascript-object) – ProllyGeek Dec 10 '13 at 03:10
  • Maybe your object should be broken up into two objects. You could either have a sub-object on the main one, or you could have the main one inherit from the ones with the `imageIds` properties so that you could simply grab it from the prototype chain. – Blue Skies Dec 10 '13 at 03:20
  • note: there is *no* order in an object's properties/methods. Any order perceived in browsers (upon testing) are 'by accident' and *not* per spec! In other words, it often works, but there is no guarantee. – GitaarLAB Dec 10 '13 at 03:45

5 Answers5

42

Some functional style awesomeness:

var data = {
    title: 'fsdfsd',
    titleZh: 'fsdfsd',
    body: 'fsdf',
    bodyZh: 'sdfsdf',
    imageIds: '/uploads/tmp/image-3.png',
    imageIdsZh: '' 
};

var z = Object.keys(data).filter(function(k) {
    return k.indexOf('imageIds') == 0;
}).reduce(function(newData, k) {
    newData[k] = data[k];
    return newData;
}, {});

console.log(z);

Demo: http://jsfiddle.net/ngX4m/

Some minor explanation:

  1. We use Array.prototype.filter() function to filter out the keys that start with `imageIds2
  2. We use Array.prototype.reduce() to convert an array of filtered keys into an object of key-value pairs. For that we use the initial value of {} (an empty object), fill it and return from every execution step.

UPD:

A fair update from @GitaarLAB:

Object.keys is ES5, but returns an objects own properties (so no need for obj.hasOwnProperty(key))

adiga
  • 34,372
  • 9
  • 61
  • 83
zerkms
  • 249,484
  • 69
  • 436
  • 539
  • 2
    No need of `reduce` here, I think. – thefourtheye Dec 10 '13 at 03:16
  • @scrblnrd3: any particular question? – zerkms Dec 10 '13 at 03:16
  • I didn't know about `reduce()` that's awesome :) +1 Cheers. – Dimitar Dimitrov Dec 10 '13 at 03:19
  • You could shorten it a little if you skipped the `.filter()` and just used `.reduce()`. – Blue Skies Dec 10 '13 at 03:21
  • @Blue Skies: that's the point - you chain functions each of which independently does its part of the work – zerkms Dec 10 '13 at 03:22
  • Yeah, I just don't see the benefit of having the condition in one iteration, and the object creation in the next. If they were reusable functions performing more complex tasks, then I could see it. – Blue Skies Dec 10 '13 at 03:24
  • @Blue Skies: it's just a normal responsibility separation. You're splitting the task into chunks. So the benefit - is more predictable design. – zerkms Dec 10 '13 at 03:25
  • 2
    OK, I'll buy that explanation. ;-) – Blue Skies Dec 10 '13 at 03:27
  • 2
    @Blue Skies: that's good because I don't have a better one ;-) It's just more natural for me – zerkms Dec 10 '13 at 03:28
  • @zerkms: I like it, but see my answer for an alternative when you add more functional goodness alongside what comes with the language. – Scott Sauyet Dec 10 '13 at 04:05
  • 1
    I think this is important to add: `Object.keys` is ES5, but returns an objects own properties (*so no need for* `obj.hasOwnProperty(key)` ). See https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys I wonder, Is this (significantly) faster then other solutions (like the one I answered here)? – GitaarLAB Dec 10 '13 at 04:31
  • Side note: This does not work in React because it says that 'newData' and 'data' aren't arrays that can be indexed with strings (k is a string). Only int indices allowed. – jeancallisti Jul 04 '19 at 09:32
2

Depending on how large the object is, this may not scale well, but it will work

for(key in obj){
   if(obj.hasOwnProperty(key)){
      if(key.indexOf("imageIds")===0){
        //do something
      }
   }
}
scrblnrd3
  • 7,228
  • 9
  • 33
  • 64
1

One also needs to use hasOwnProperty in conjunction with the for-in loop (not mentioned in most current previous answers).
Reason is that the for-in loop will also go over the methods/properties that an object would inherit from the proto-type chain (should someone or some library have added custom stuff).

So you are looking for something simple and reliable like this:

function fetch(obj, str){
    var key, results = [];
    for(key in obj) obj.hasOwnProperty(key) 
                 && key.indexOf(str) === 0 
                 && results.push([ key, obj[key] ]);
    return results;
}

Note: you could also name this function 'getAllKeysAndValuesStartingWith' (or gakavsw should you work for the army haha).

Usage:

fetch(object, string) returns a simple (to loop over) array with found results,
so var my_results = fetch(testObj, 'imageId'); would give the following output:

[ //array of arrays
  ['imageIds', '/uploads/tmp/image-3.png']
, ['imageIdsZh', '']                               /* 
, [key, value]           and more if it finds them */
]

Working jsfiddle here.

Naturally one could also push just the values: results.push(obj[key])
I would recommend against returning an object ( (results[key]=obj[key]) ) since the array is easier to work with in this case.

Hope this helps!

GitaarLAB
  • 14,536
  • 11
  • 60
  • 80
1

Along the lines of the answer from @zerkms, I've been working on a functional programming library for Javascript. With the tools from that library, this turns into a (somewhat dense) one-liner:

var data = {
    title: 'fsdfsd',
    titleZh: 'fsdfsd',
    body: 'fsdf',
    bodyZh: 'sdfsdf',
    imageIds: '/uploads/tmp/image-3.png',
    imageIdsZh: '' 
};

var x = pick(filter(compose(eq("imageIds"), substring(0,8)), keys(data)), data);
console.log(x);

This code is not necessarily any better than what @zerkms posted, but it does show off some more of the power of functional abstractions beyond the few that are built into Array.prototype.

You can see it in action on JSFiddle.

Community
  • 1
  • 1
Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
0
 // json to be searched
var data = {
    title: 'fsdfsd',
    titleZh: 'fsdfsd',
    body: 'fsdf',
    bodyZh: 'sdfsdf',
    imageIds: '/uploads/tmp/image-3.png',
    imageIdsZh: '' 
};


// takes the json 'data' as its 1st parameter
// and the desired 'property' to be searched as the 2nd parameter
// for loop iterates through the entire json
// if the property parameter matches a 'key' name in json e.g. 'imageIds'
// then the value for that property is returned
function fetchProperty (data, property) {
    for(var key in data) {
        if(key === property) {
            return data[key];
        }   
    }
}


// if you wanted to return a bunch of data according to a particular key - value pair
// you could do something like this...
// assume 'array' contains a bunch of jsons 
// newData will hold jsons containing your newly fetched data points
function fetchNewData() {
   var newData = [];
   for(var i = 0; i < array.length; i++) {

      var value1 = fetchProperty(array[i], 'imageIds');
      var value2 = fetchProperty(array[i], 'imageIdsZh');
      var value3 = fetchProperty(array[i], 'imageIdsBlah');

      var tempJSON = {};
      tempJSON.imageIds = value1;
      tempJSON.imageIdsZh = value2;
      tempJSON.imageIdsBlah = value3;

      newData.push(tempJSON);
   }
   return newData;
}    

** I hope this was helpful. If you have any further questions, feel free to reach out. Best of luck. **

user548
  • 31
  • 1
  • 6
  • you have hardcoded the key-names which is specifically the asker did not want to, the whole purpose of his question. – GitaarLAB Dec 10 '13 at 04:20