I'm trying return an object from the code below that has the key value pair of name:sparky and return the entire metadata and stats array for that object.
I don't want to use Object.values(objectArray)[0] because this data is coming from an API and I expect the objects position in the array to change in the future.
I've tried objectArray.find but I don't know how to use that to find a value of an array which is inside another array. The value for name will always be unique and the actual objectArray has many more objects inside of it.
Help would be greatly appreciated!
Code
objectArray = [
{
"metadata": [
{
"key": '1',
"name": "sparky"
}
],
"stats": [
{
"statsFieldOne": "wins"
},
{
"statsFieldTwo": "kills"
}
]
},
{
"metadata": [
{
"key": '1',
"name": "abby"
}
],
"stats": [
{
"statsFieldOne": "wins"
},
{
"statsFieldTwo": "kills"
}
]
}
]
Desired result
{
"metadata": [
{
"key": '1',
"name": "sparky"
}
],
"stats": [
{
"statsFieldOne": "wins"
},
{
"statsFieldTwo": "kills"
}
]
}
I guess you can do following:
function getObjectForName(key, name) {
var filteredMetadata = [];
for(var i=0; i< objectArray.length; i++) {
filteredMetadata = objectArray[i].metadata.filter((val) => val[key] === name)
if(filteredMetadata.length) {
return objectArray[i];
}
}
}
getObjectForName('name', 'sparky')
What this code basically does is, iterates through all objects and check if name is sparky, if yes just break it. If you want to return all occurrences matching name, you need to add all of them to another array and return it.
You can simply use Reduce
let objectArray = [{"metadata":[{"key":'1',"name":"sparky"}],"stats":[{"statsFieldOne":"wins"},{"statsFieldTwo":"kills"}]},{"metadata":[{"key":'1',"name":"abby"}],"stats":[{"statsFieldOne":"wins"},{"statsFieldTwo":"kills"}]}]
let op = objectArray.reduce(( op,{metadata,stats} ) =>{
let found = metadata.find(({name})=>name==='sparky')
if(found){
op.push({metadata:found,stats})
}
return op
},[])
console.log(op)
Suppose I have object
let x = { "people" :{
"Sally": "value",
"Bob" : "other value"
},
"cars" :{
"Saab" : "this",
"Chevy": "that"
},
"trees":{
"Birch" : "what",
"Oak" : "where"
}
}
I want to search, so if I searched for "S" I'd get back an array that was
{ "people" :{
"Sally": "value",
},
"cars" :{
"Saab" : "this",
}
}
And if I searched for "b" I'd get:
{ "people" :{
"Bob" : "other value"
},
"trees":{
"Birch" : "what",
}
}
or "bo" would return
{ "people" :{
"Bob" : "other value"
}
And if I searched "e" I'd get
{ "cars" :{
"Chevy": "that"
}
}
Note that the "people" and "trees" isn't caught by the search for 'e'.
The strut will be of a fixed depth, and we only ever want to catch keys that match the filter and don't have children (we're also not interested in values that match, just keys).
Adding npm dependencies is acceptable.
Attempted solution:
filteredList(unfiltered,searchVal) {
return unfiltered.filter(search=> {
return search.toLowerCase().includes(searchVal.toLowerCase())
})
}
Obviously there's more to it, but I'm not sure which direction to proceed.
This is a basic attempt. It's seems work quite fine but I'm very sure that it may be possible to make even better. But I don't know how.
let x = {
"people": {
"Sally": "value",
"Bob": "other value"
},
"cars": {
"Saab": "this",
"Chevy": "that"
},
"trees": {
"Birch": "what",
"Oak": "where"
}
}
let search = "B";
let result = {};
for (let key in x) {
let tmp = {};
for (let subKey in x[key]) {
if (subKey.includes(search)) { // Use startsWithif you want even substring that aren't at the beginning
tmp[subKey] = x[key][subKey];
}
if (Object.keys(tmp).length > 0) {
result[key] = Object.assign({}, tmp);
}
}
}
console.log(result)
If you want an arbitrary deep, you should try with some kind of recursion, but that will be more complex.
Here's a solution that uses the lodash library. Lodash has a number of super useful methods for object manipulation, in this case _.pickBy and _.mapValues can be used to filter your nested object.
Example:
let x = {
"people": {
"Sally": "value",
"Bob": "other value"
},
"cars": {
"Saab": "this",
"Chevy": "that"
},
"trees": {
"Birch": "what",
"Oak": "where"
}
}
function search(query) {
query = query.toLowerCase();
const matched = _.mapValues(x, v => _.pickBy(v, (_, k) => k.toLowerCase().includes(query)));
return _.pickBy(matched, v => Object.keys(v).length)
}
console.log(search("S"))
console.log(search("b"))
console.log(search("bo"))
console.log(search("e"))
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.5/lodash.min.js"></script>
I have a list of objects. On each object I have an array.
Example:
"-KpvPH2_SDssxZ573OvM" : {
"date" : "2017-07-25T20:21:13.572Z",
"description" : "Test",
"id" : [ {
0: "0a477fed-8944-9f5d-56fd-c95fe7663a07",
1: "0a477fed-8944-9f5d-56fd-c95fe7663a08"
} ]
},
"-KpvPLSfotrZiBDeVOxU" : {
"date" : "2017-07-25T20:21:33.159Z",
"description" : "Test 2",
"id" : [ {
0: "6e79eadd-21b5-91cc-4b71-7ac1a42278b1"
} ]
}
How do I search for an object using the ID array as a parameter?
When I need to filter only one array I use filter and everything works ok.
var result = $.grep(items, function(e){ return e.id == id; });
But in this case I believe it does not work.
Thanks
Since the ID's are a little deeper in the object, and they are part of an object, I think a better approach (as compared to $.grep) would be a custom filter. Here I have assumed you want exact comparison while filtering, based on your question. But you could easily have partial comparison with indexOf as well.
var data = {
"-KpvPH2_SDssxZ573OvM": {
"date": "2017-07-25T20:21:13.572Z",
"description": "Test",
"id": [{
0: "0a477fed-8944-9f5d-56fd-c95fe7663a07",
1: "0a477fed-8944-9f5d-56fd-c95fe7663a08"
}]
},
"-KpvPLSfotrZiBDeVOxU": {
"date": "2017-07-25T20:21:33.159Z",
"description": "Test 2",
"id": [{
0: "6e79eadd-21b5-91cc-4b71-7ac1a42278b1"
}]
}
};
//console.log(data);
var inputID = "0a477fed-8944-9f5d-56fd-c95fe7663a08";
var filteredData = [];
for (var prop in data) {
if(data.hasOwnProperty(prop)) {
var item = data[prop];
var itemIDs = item.id[0];
for(var id in itemIDs) {
if (itemIDs[id] == inputID) {
filteredData.push(item);
}
}
}
}
console.log(filteredData);
var a = {
"title": "Test 1",
"likes": {
"id": 1
}
}
var b = {
"title": "Test 2",
"likes": {
"id": 2
}
}
var c = [a, b];
var d = _.where(c, {
"title": "Test 2",
"likes": {
"id": 2
}
});
//d => outputs an empty array []
In this situation i would expect to get the reference to object in memory but d
but actually it just works on root properties.
_.where(c, {title: "Test 2"});
=> outputs [object]
where object is the reference for c[1];
EDIT:
found a possible solution using _.filter()
_.filter( c, function(item){
if (item.title == "Test 1" && item.likes.id == 1){
return item;
}
})
outputs => [object] with reference for variable a
_.filter is the right way to do this, _.where is just a _.filter shortcut for filtering on simple key/value pairs. You can see this from the source:
// Convenience version of a common use case of `filter`: selecting only objects
// containing specific `key:value` pairs.
_.where = function(obj, attrs, first) {
if (_.isEmpty(attrs)) return first ? void 0 : [];
return _[first ? 'find' : 'filter'](obj, function(value) {
for (var key in attrs) {
if (attrs[key] !== value[key]) return false;
}
return true;
});
};
The docs could be a little more explicit but at least the comment in the source is clear.
I have a JSON file containing some data I d like to access on my AngularJS website. Now what I want is to get only one object from the array. So I d like for example Item with id 1.
The data looks like this:
{ "results": [
{
"id": 1,
"name": "Test"
},
{
"id": 2,
"name": "Beispiel"
},
{
"id": 3,
"name": "Sample"
}
] }
I'd like to load the data with AngularJS $http functionality like this:
$http.get("data/SampleData.json");
which is working. But how can I now get a specific data object (by id) from the array I get from $http.get ?
Using ES6 solution
For those still reading this answer, if you are using ES6 the find method was added in arrays. So assuming the same collection, the solution'd be:
const foo = { "results": [
{
"id": 12,
"name": "Test"
},
{
"id": 2,
"name": "Beispiel"
},
{
"id": 3,
"name": "Sample"
}
] };
foo.results.find(item => item.id === 2)
I'd totally go for this solution now, as is less tied to angular or any other framework. Pure Javascript.
Angular solution (old solution)
I aimed to solve this problem by doing the following:
$filter('filter')(foo.results, {id: 1})[0];
A use case example:
app.controller('FooCtrl', ['$filter', function($filter) {
var foo = { "results": [
{
"id": 12,
"name": "Test"
},
{
"id": 2,
"name": "Beispiel"
},
{
"id": 3,
"name": "Sample"
}
] };
// We filter the array by id, the result is an array
// so we select the element 0
single_object = $filter('filter')(foo.results, function (d) {return d.id === 2;})[0];
// If you want to see the result, just check the log
console.log(single_object);
}]);
Plunker: http://plnkr.co/edit/5E7FYqNNqDuqFBlyDqRh?p=preview
For anyone looking at this old post, this is the easiest way to do it currently. It only requires an AngularJS $filter. Its like Willemoes answer, but shorter and easier to understand.
{
"results": [
{
"id": 1,
"name": "Test"
},
{
"id": 2,
"name": "Beispiel"
},
{
"id": 3,
"name": "Sample"
}
]
}
var object_by_id = $filter('filter')(foo.results, {id: 2 })[0];
// Returns { id: 2, name: "Beispiel" }
WARNING
As #mpgn says, this doesn't work properly. This will catch more results. Example: when you search 3 this will catch 23 too
personally i use underscore for this kind of stuff... so
a = _.find(results,function(rw){ return rw.id == 2 });
then "a" would be the row that you wanted of your array where the id was equal to 2
I just want to add something to Willemoes answer.
The same code written directly inside the HTML will look like this:
{{(FooController.results | filter : {id: 1})[0].name }}
Assuming that "results" is a variable of your FooController and you want to display the "name" property of the filtered item.
You can use ng-repeat and pick data only if data matches what you are looking for using ng-show
for example:
<div ng-repeat="data in res.results" ng-show="data.id==1">
{{data.name}}
</div>
You can just loop over your array:
var doc = { /* your json */ };
function getById(arr, id) {
for (var d = 0, len = arr.length; d < len; d += 1) {
if (arr[d].id === id) {
return arr[d];
}
}
}
var doc_id_2 = getById(doc.results, 2);
If you don't want to write this messy loops, you can consider using underscore.js or Lo-Dash (example in the latter):
var doc_id_2 = _.filter(doc.results, {id: 2})[0]
If you want the list of items like city on the basis of state id then use
var state_Id = 5;
var items = ($filter('filter')(citylist, {stateId: state_Id }));
Unfortunately (unless I'm mistaken), I think you need to iterate over the results object.
for(var i = 0; i < results.length; i += 1){
var result = results[i];
if(result.id === id){
return result;
}
}
At least this way it will break out of the iteration as soon as it finds the correct matching id.
Why complicate the situation? this is simple write some function like this:
function findBySpecField(data, reqField, value, resField) {
var container = data;
for (var i = 0; i < container.length; i++) {
if (container[i][reqField] == value) {
return(container[i][resField]);
}
}
return '';
}
Use Case:
var data=[{
"id": 502100,
"name": "Bərdə filialı"
},
{
"id": 502122
"name": "10 saylı filialı"
},
{
"id": 503176
"name": "5 sayli filialı"
}]
console.log('Result is '+findBySpecField(data,'id','502100','name'));
output:
Result is Bərdə filialı
The only way to do this is to iterate over the array. Obviously if you are sure that the results are ordered by id you can do a binary search
$scope.olkes = [{'id':11, 'name':'---Zəhmət olmasa seçim edin---'},
{'id':15, 'name':'Türkyə'},
{'id':45, 'name':'Azərbaycan'},
{'id':60, 'name':'Rusya'},
{'id':64, 'name':'Gürcüstan'},
{'id':65, 'name':'Qazaxıstan'}];
<span>{{(olkes | filter: {id:45})[0].name}}</span>
output: Azərbaycan
If you can, design your JSON data structure by making use of the array indexes as IDs. You can even "normalize" your JSON arrays as long as you've no problem making use of the array indexes as "primary key" and "foreign key", something like RDBMS. As such, in future, you can even do something like this:
function getParentById(childID) {
var parentObject = parentArray[childArray[childID].parentID];
return parentObject;
}
This is the solution "By Design". For your case, simply:
var nameToFind = results[idToQuery - 1].name;
Of course, if your ID format is something like "XX-0001" of which its array index is 0, then you can either do some string manipulation to map the ID; or else nothing can be done about that except through the iteration approach.
I know I am too late to answer but it's always better to show up rather than not showing up at all :). ES6 way to get it:
$http.get("data/SampleData.json").then(response => {
let id = 'xyz';
let item = response.data.results.find(result => result.id === id);
console.log(item); //your desired item
});
The simple way to get (one) element from array by id:
The find() method returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.
function isBigEnough(element) {
return element >= 15;
}
var integers = [12, 5, 8, 130, 160, 44];
integers.find(isBigEnough); // 130 only one element - first
you don't need to use filter() and catch first element xx.filter()[0] like in comments above
The same for objects in array
var foo = {
"results" : [{
"id" : 1,
"name" : "Test"
}, {
"id" : 2,
"name" : "Beispiel"
}, {
"id" : 3,
"name" : "Sample"
}
]};
var secondElement = foo.results.find(function(item){
return item.id == 2;
});
var json = JSON.stringify(secondElement);
console.log(json);
Of course if you have multiple id then use filter() method to get all objects.
Cheers
function isBigEnough(element) {
return element >= 15;
}
var integers = [12, 5, 8, 130, 160, 44];
integers.find(isBigEnough); // 130 only one element - first
var foo = {
"results" : [{
"id" : 1,
"name" : "Test"
}, {
"id" : 2,
"name" : "Beispiel"
}, {
"id" : 3,
"name" : "Sample"
}
]};
var secondElement = foo.results.find(function(item){
return item.id == 2;
});
var json = JSON.stringify(secondElement);
console.log(json);
projectDetailsController.controller('ProjectDetailsCtrl', function ($scope, $routeParams, $http) {
$http.get('data/projects.json').success(function(data) {
$scope.projects = data;
console.log(data);
for(var i = 0; i < data.length; i++) {
$scope.project = data[i];
if($scope.project.name === $routeParams.projectName) {
console.log('project-details',$scope.project);
return $scope.project;
}
}
});
});
Not sure if it's really good, but this was helpful for me..
I needed to use $scope to make it work properly.
use $timeout and run a function to search in "results" array
app.controller("Search", function ($scope, $timeout) {
var foo = { "results": [
{
"id": 12,
"name": "Test"
},
{
"id": 2,
"name": "Beispiel"
},
{
"id": 3,
"name": "Sample"
}
] };
$timeout(function () {
for (var i = 0; i < foo.results.length; i++) {
if (foo.results[i].id=== 2) {
$scope.name = foo.results[i].name;
}
}
}, 10);
});
I would iterate over the results array using an angularjs filter like this:
var foundResultObject = getObjectFromResultsList(results, 1);
function getObjectFromResultsList(results, resultIdToRetrieve) {
return $filter('filter')(results, { id: resultIdToRetrieve }, true)[0];
}