I'm new to javascript and I'm not sure about the best way to store data.
I'll write an example about what I want to obtain:
Country1
Country informations
Region1
Region informations
Place1
Place informations
Place2
Place informations
Region2
Region informations
Place1
Place informations
Place2
Place informations
Country2
Country informations
Region1
Region informations
Place1
Place informations
Place2
Place informations
Region2
Region informations
Place1
Place informations
Place2
Place informations
...
Consider "informations" as different values like x, y, name, ecc...
I want to be able to access these properties in an easy way, something like 1-1-2-x
The best solution that came to my mind was to use a 4d array to store "place informations", a 3d one to store "Region informations" and a matrix to store "country informations"
Do you think this is the best solution? I hope my explanation is understandable, thanks.
I think JSON is what you're after.
Example:
var data = {
countries : [
{
name: 'country1',
regions: [
{
name: 'region1',
places: [
{
name: 'place1'
}
]
}
]
}
]
};
Here we have an array of countries. Each country can have an array of regions. Each region, an array of places.
You can consume this by indexes:
var place = data.contries[0].regions[0].places[0].name;
Or you can write custom methods to access by name:
var data = {
getCountry : function(name) {
var len = this.countries.length;
for (var i = 0; i < len; i++) {
if (name === this.countries[i].name)
return this.countries[i];
}
return null;
},
countries : [
{
getRegion : function(name) {
var len = this.regions.length;
for (var i = 0; i < len; i++) {
if (name === this.regions[i].name)
return this.regions[i];
}
return null;
},
name: 'country1',
regions: [
{
name: 'region1',
places: [
{
name: 'place1'
}
]
}
]
}
]
};
Usage:
var region = data.getCountry('county1').getRegion('region1');
Verbose data example:
var data = {
countries : [
{
name: 'country1',
regions: [
{
name: 'region1',
places: [
{
name: 'place1'
},
{
name: 'place2'
}
]
},
{
name: 'region2',
places: [
{
name: 'place3'
},
{
name: 'place4'
}
]
}
]
},
{
name: 'country2',
regions: [
{
name: 'region3',
places: [
{
name: 'place5'
},
{
name: 'place6'
}
]
},
{
name: 'region4',
places: [
{
name: 'place7'
},
{
name: 'place8'
}
]
}
]
}
]
};
You could create JSON objects for your data and store in a MongoDB. There's some documentation here how to store and retrieve the data.
There's an article here for further understanding, so you can see how to create the JSON object(s), it will then be up to you how you want to store them.
Storing this amount of data in client-side without Ajax requests is not suggested. However what will I do at this moment is this:
var data= new Array()
data["US"] = new Array();
data["US"]["Info"] = "United Stats Information...";
data["US"]["Arizona"] = new Array();
data["US"]["Arizona"]["Info"] = "Region Info...";
data["US"]["Arizona"]["placeA"] = "PlaceA Info!";
data["US"]["Arizona"]["placeB"] = "PlaceB Info!";
Related
I have an object in an array called "Person".
Within the object "Person", there is an array called "info".
My goal is to get all the values with the prefix "age:" in an array "info" when filtering by "gender:male". So, my desired output will be 1 to 9 because I want also to remove duplicates.
Below is my code but the results are only two values (1 and 4). Maybe the output is one value per person.
I spent a lot of hours playing the code but no luck. That's why I bring my problem here hoping anybody who is an expert on this can help me.
<script>
var array = [
{
"person": {
"info": [
"age:1",
"age:2",
"age:3",
"age:4",
"age:5",
"age:6",
"gender:male"
]
},
"person": {
"info": [
"age:4",
"age:5",
"age:6",
"age:7",
"age:8",
"age:9",
"gender:male"
]
},
"person": {
"info": [
"age:8",
"age:9",
"age:10",
"age:11",
"age:12",
"age:13",
"gender:female"
]
}
}
]
var filteredAges = [];
for (i = 0; i < array.length; i++) {
var infoGroup = array[i].person.info,
ageGroup = [];
for (j = 0; j < infoGroup.length; j++) {
ageGroup.push(infoGroup[j]);
var ageInfo = ageGroup.find(ages => ages.includes('age:'));
};
if (ageInfo) {
if (filteredAges.indexOf(ageInfo) == -1) {
filteredAges.push(ageInfo)
}
}
}
for (i = 0;i < filteredAges.length; i++) {
console.log(filteredAges[i]);
}
</script>
Seems like all your object keys are just person i.e
[
{
person: {...},
person: {...},
person: {...}
}
]
So when the variable array is evaluated it just has one person
You need to restructure your data maybe like below or something similar
Example - 1
[
{ person: {...} },
{ person: {...} },
{ person: {...} },
]
Example - 2
[
[ { person: {...} } ],
[ { person: {...} } ],
[ { person: {...} } ]
]
After fixing this you can try debugging your problem
If you want to get all items in info array that has "age:"
you can use filter like this
const ageInfos = [
"age:8", "age:9",
"age:10", "age:11",
"age:12", "age:13",
"gender:female"
].filter(x => x.startsWith("age:"))
Your output - ageInfos will be
["age:8", "age:9", "age:10", "age:11", "age:12", "age:13"]
You can also use Set to only collect unique strings or just push everything to an array and later use Set to return only unique values like this
const arrayWithDuplicates = ['a', 1, 'a', 2, '1'];
const unique = [...new Set(arrayWithDuplicates)];
console.log(unique); // unique is ['a', 1, 2, '1']
First of all, your JSON is wrong. You just overright person object.
Data structure is really awful, I would recommend you to rethink it.
Assuming person will not be overwritten I came up with this solution.
var array = [
{
"person": {
"info": [
"age:1",
"age:2",
"age:3",
"age:4",
"age:5",
"age:6",
"gender:male"
]
},
"person1": {
"info": [
"age:4",
"age:5",
"age:6",
"age:7",
"age:8",
"age:9",
"gender:male"
]
},
"person2": {
"info": [
"age:8",
"age:9",
"age:10",
"age:11",
"age:12",
"age:13",
"gender:female"
]
}
}
]
let agesArray = []
let ages = []
array.forEach((peopleObj) => {
for (const index in peopleObj) {
ages = peopleObj[index].info.map((age) => {
const ageNumber = age.split(':')[1]
if (parseInt(ageNumber)) {
return ageNumber
}
}).filter(val => !!val)
agesArray = [...agesArray, ...ages]
}
})
Thanks a lot guys. I'll apply all of your ideas and try if it can solve my problem.
For my scenario, I need to push elements to an addresses array which contains objects. I'm working with vue.js.
My current working function is:
propagateCustomerInfo(selectedOption, id){
// Propagate addresses
this.addresses = selectedOption.addresses
// Propagate contact's addresses
for (var i = selectedOption.contacts.length - 1; i >= 0; i--) {
for (var j = selectedOption.contacts[i].addresses.length - 1; j >= 0; j--) {
let address = selectedOption.contacts[i].addresses[j]
address.contact = selectedOption.contacts[i]
this.addresses.push(address)
}
}
},
the selectedOption object has the below structure:
{
addresses: [
{
id: 0,
street: 'My street'
},
{...}
],
contacts: [
{
id: 0,
name: 'Lorem Ipsum',
addresses: [
{
id: 0,
street: 'My street'
},
{...}
],
}
]
}
Besides pushing every contact's address object to this.addresses array I need to append the contact to the address itself for multiselect rendering purposes. That's why I'm doing address.contact = selectedOption.contacts[i]
I almost sure that this can be accomplished in a prettiest way with some mapping/reduce combination but I can't figure out how to do it.
Any help will be really appreciated.
Thanks!
if you want to combine all address in contact variable to addresses variable:
this.contacts.map(contact => this.addresses.push(...contact.addresses))
Edit.
to inject the contact.id and contact.name:
this.contacts.map(contact => {
let temp = []
contact.addresses.map(address => {
temp.push({
name: contact.name,
id: contact.id,
...address
})
})
this.addresses.push(...temp)
})
I use an api which returns an object 'results'. The 'results' object holds other objects which have type article or detail.
Each one of the the result (article or detail) contain their own object results with different pages of that type.
What i want to do: store the results in an array 'pages' where i order them by all the articles first then all the details
I want to sort them in the array because I need to display the articles first then the detail pages in the frontend.
var pages = [];
_.find(results, function(r) {
if(r.type === 'article') {
_.forEach(r.results, function(p) {
p.type = 'article';
pages.push(r);
});
} else if(r.app === 'detail') {
_.forEach(r.results, function(p) {
p.type = 'detail';
pages.push(p);
});
}
});
This was my attempt with Lodash find but in the frontend i still have results where the details are displayed after the articles.
Note: The api result can be like this: {detail}, {article} but also like this {detail}, {article}, {detail}, {article}
Sample data:
results: [
{
type: 'article',
results: {
{
title: '',
body: '',
...
},
...
}
},
{
type: 'detail',
results: {
{
title: '',
body: '',
...
},
...
}
},
...
]
After a long dicussion :
var sorted;
var articles = [];
var details = [];
var source = [{
app: "article",
results: [
{ title: "a" },
{ title: "b" },
{ title: "c" }
]
}, {
app: "detail",
results: [
{ title: "d" },
{ title: "e" },
{ title: "f" }
]
}, {
app: "article",
results: [
{ title: "g" },
{ title: "h" },
{ title: "i" }
]
}];
for (var i = 0; i < source.length; i++) {
switch (source[i].app) {
case "article": articles = articles.concat(source[i].results); break;
case "detail": details = details.concat(source[i].results); break;
}
}
sorted = articles.concat(details);
console.log("articles =", JSON.stringify(articles));
console.log("details =", JSON.stringify(details));
console.log("sorted =", JSON.stringify(sorted));
console.log("source =", JSON.stringify(source));
I have an array like this
$scope.dogs = [
{ id: 1, breed: 'German Shepherd' },
{ id: 2, breed: 'Collie' }
]
And a second array like this:
$scope.owners = [
{ name: 'Mary', breedowned: 'German Shepherd' },
{ name: 'Bill', breedowned: 'German Shepherd' },
{ name: 'Bob', breedowned: 'Collie' }
]
I want to push the list of owners into the list of dogs like so basically creating:
$scope.dogs = [
{ id: 1, breed: 'German Shepherd', owners: [...] }
]
I tried to use forEach and push the owners into the dogs array, but it does not work.
angular.forEach($scope.dogs, function (value, key) {
for (x = 0; x < $scope.owners.length; x++) {
if ($scope.owners[i].breedowned == value.breed) {
$scope.dogs[key].owners.push($scope.owners[i])
}
}
});
Thanks for any help!
If you don't want any form of dependency, just use Array.prototype.push.apply, this way:
Array.prototype.push.apply($scope.owners, $scope.dogs);
You didnt mention any errors, but I see an issue with you missing var in front of the x in the for loop, and also owners is not initialized in the dog object. Here's a consistent nested loop solution:
angular.forEach($scope.dogs, function (dog) {
angular.forEach($scope.owners, function (owner) {
if (owner.breedowned == dog.breed) {
dog.owners = dog.owners || []
dog.owners.push(owner)
}
})
})
Here a better solution that only goes through the owners array once and only through the dogs array once.
var tracker = $scope.owners.reduce(function(trackerObj, owner){
var breedowned = owner.breedowned;
trackerObj[breedowned] = trackerObj[breedowned] || [];
trackerObj[breedowned].push(owner);
return trackerObj;
}, {});
$scope.dogs.forEach(function(dog){
dog.owners = tracker[dog.breed];
});
I have an array of objects:
Object = {
1 : { name : bob , dinner : pizza },
2 : { name : john , dinner : sushi },
3 : { name : larry, dinner : hummus }
}
I want to be able to search the object/array for where the key is "dinner", and see if it matches "sushi".
I know jQuery has $.inArray, but it doesn't seem to work on arrays of objects. Or maybe I'm wrong. indexOf also seems to only work on one array level.
Is there no function or existing code for this?
If you have an array such as
var people = [
{ "name": "bob", "dinner": "pizza" },
{ "name": "john", "dinner": "sushi" },
{ "name": "larry", "dinner": "hummus" }
];
You can use the filter method of an Array object:
people.filter(function (person) { return person.dinner == "sushi" });
// => [{ "name": "john", "dinner": "sushi" }]
In newer JavaScript implementations you can use a function expression:
people.filter(p => p.dinner == "sushi")
// => [{ "name": "john", "dinner": "sushi" }]
You can search for people who have "dinner": "sushi" using a map
people.map(function (person) {
if (person.dinner == "sushi") {
return person
} else {
return null
}
}); // => [null, { "name": "john", "dinner": "sushi" }, null]
or a reduce
people.reduce(function (sushiPeople, person) {
if (person.dinner == "sushi") {
return sushiPeople.concat(person);
} else {
return sushiPeople
}
}, []); // => [{ "name": "john", "dinner": "sushi" }]
I'm sure you are able to generalize this to arbitrary keys and values!
jQuery has a built-in method jQuery.grep that works similarly to the ES5 filter function from #adamse's Answer and should work fine on older browsers.
Using adamse's example:
var peoples = [
{ "name": "bob", "dinner": "pizza" },
{ "name": "john", "dinner": "sushi" },
{ "name": "larry", "dinner": "hummus" }
];
you can do the following
jQuery.grep(peoples, function (person) { return person.dinner == "sushi" });
// => [{ "name": "john", "dinner": "sushi" }]
var getKeyByDinner = function(obj, dinner) {
var returnKey = -1;
$.each(obj, function(key, info) {
if (info.dinner == dinner) {
returnKey = key;
return false;
};
});
return returnKey;
}
jsFiddle.
So long as -1 isn't ever a valid key.
If you're going to be doing this search frequently, consider changing the format of your object so dinner actually is a key. This is kind of like assigning a primary clustered key in a database table. So, for example:
Obj = { 'pizza' : { 'name' : 'bob' }, 'sushi' : { 'name' : 'john' } }
You can now easily access it like this: Object['sushi']['name']
Or if the object really is this simple (just 'name' in the object), you could just change it to:
Obj = { 'pizza' : 'bob', 'sushi' : 'john' }
And then access it like: Object['sushi'].
It's obviously not always possible or to your advantage to restructure your data object like this, but the point is, sometimes the best answer is to consider whether your data object is structured the best way. Creating a key like this can be faster and create cleaner code.
You can find the object in array with Alasql library:
var data = [ { name : "bob" , dinner : "pizza" }, { name : "john" , dinner : "sushi" },
{ name : "larry", dinner : "hummus" } ];
var res = alasql('SELECT * FROM ? WHERE dinner="sushi"',[data]);
Try this example in jsFiddle.
You can use a simple for in loop:
for (prop in Obj){
if (Obj[prop]['dinner'] === 'sushi'){
// Do stuff with found object. E.g. put it into an array:
arrFoo.push(Obj[prop]);
}
}
The following fiddle example puts all objects that contain dinner:sushi into an array:
https://jsfiddle.net/3asvkLn6/1/
There's already a lot of good answers here so why not one more, use a library like lodash or underscore :)
obj = {
1 : { name : 'bob' , dinner : 'pizza' },
2 : { name : 'john' , dinner : 'sushi' },
3 : { name : 'larry', dinner : 'hummus' }
}
_.where(obj, {dinner: 'pizza'})
>> [{"name":"bob","dinner":"pizza"}]
I had to search a nested sitemap structure for the first leaf item that machtes a given path. I came up with the following code just using .map() .filter() and .reduce. Returns the last item found that matches the path /c.
var sitemap = {
nodes: [
{
items: [{ path: "/a" }, { path: "/b" }]
},
{
items: [{ path: "/c" }, { path: "/d" }]
},
{
items: [{ path: "/c" }, { path: "/d" }]
}
]
};
const item = sitemap.nodes
.map(n => n.items.filter(i => i.path === "/c"))
.reduce((last, now) => last.concat(now))
.reduce((last, now) => now);
If You want to find a specific object via search function just try something like this:
function findArray(value){
let countLayer = dataLayer.length;
for(var x = 0 ; x < countLayer ; x++){
if(dataLayer[x].user){
let newArr = dataLayer[x].user;
let data = newArr[value];
return data;
}
}
return null;
}
findArray("id");
This is an example object:
layerObj = {
0: { gtm.start :1232542, event: "gtm.js"},
1: { event: "gtm.dom", gtm.uniqueEventId: 52},
2: { visitor id: "abcdef2345"},
3: { user: { id: "29857239", verified: "Null", user_profile: "Personal", billing_subscription: "True", partners_user: "adobe"}
}
Code will iterate and find the "user" array and will search for the object You seek inside.
My problem was when the array index changed every window refresh and it was either in 3rd or second array, but it does not matter.
Worked like a charm for Me!
In Your example it is a bit shorter:
function findArray(value){
let countLayer = Object.length;
for(var x = 0 ; x < countLayer ; x++){
if(Object[x].dinner === value){
return Object[x];
}
}
return null;
}
findArray('sushi');
We use object-scan for most of our data processing. It's conceptually very simple, but allows for a lot of cool stuff. Here is how you would solve your question
// const objectScan = require('object-scan');
const findDinner = (dinner, data) => objectScan(['*'], {
abort: true,
rtn: 'value',
filterFn: ({ value }) => value.dinner === dinner
})(data);
const data = { 1: { name: 'bob', dinner: 'pizza' }, 2: { name: 'john', dinner: 'sushi' }, 3: { name: 'larry', dinner: 'hummus' } };
console.log(findDinner('sushi', data));
// => { name: 'john', dinner: 'sushi' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.8.0"></script>
Disclaimer: I'm the author of object-scan