Dynamiccaly accessing array inside objects inside arrays - javascript

First of all, i am relatively new to javascript so go easy on me :)
Here is my problem. I need to be able to dynamically navigate a multidimensionnal array that look like such :
Categories:[
{id:cat1,
name:cat1,
childrens:[
{id:cat1-subcat1,
name:cat1-subcat1,
childrens:[
{id:cat1-subcat1-subcat1,
name:cat1-subcat1-subcat1,
childrens:[
etc...
The idea is as follow : the client can create categories and nest subcategories under them but also put sub categories inside subcategories.
So i can add a subcategorie to a categorie by doing :
categories[position].children.push(newcat)
Now my problem is how to do the same with a sub categorie.
categories[position].children[x].children.push(newcat)
getting the x value and storing it in the new created categorie could be possible and i guess i could work my way around 1 layer of subcatgories but the idea is that it is supposed to be able to create as many nested sub categories as necessaries. so it could look like :
categories[position].children[x].children[y].children[z].children.push(newcat)
So i need a dynamic way to access those places. not sur how to do it.
Can i access those nested object via their id ? like with map in a regular array.
How would i access cat1-subcat1-subcat1 with only knowing the id for exemple ???
I hope it make sens, i am availbale of course for more explanations
Thanks, Esteban

So i have been trying to work on that piece of code.
To break down a simple array into a multidimensionnal one.
Each categorie store a level and parentid value.
Here is the code i am trying to work on,
Hope it makes sens to you guys. Again sorry for my poor javascript skill, that code very likely can be optimized.
Right now i would just like it to work :)
buildTreeview2(){
var catdb = this.$catdb
var lvl=0
var temparray=[]
var temparray2=[]
var tempactif=1
//var init = true
var j
var u
var i
//console.log({catdb})
// count how many lvls max
for(i=0;i<catdb.length;i++){
if (catdb[i].level>lvl){lvl=catdb[i].level}
}
if(lvl==0){
this.categories=this.$catdb
}
else{
for(u=lvl;u>=0;u--){
//console.log(u)
//put the items with the current lvl in an array
for(i=0;i<catdb.length;i++){
//console.log(catdb[i].level)
if(tempactif==1){
if(catdb[i].level==lvl){
temparray.push(catdb[i])
}
}else{
if(catdb[i].level==lvl){
temparray2.push(catdb[i])
}
}
}
//check if first round with init value
// if(init==true){
// tempactif=2
// init=false
// continue}
// else{
// add item from supperior lvl array to lower one
if(tempactif==1){
for(i=0;i<temparray.length;i++){
for(j=0;j<temparray2.length;j++){
if(temparray[i].id==temparray2[j].parentid){
temparray[i].children.push(temparray2[j])
}
}
}
}else{
for(i=0;i<temparray2.length;i++){
console.log(temparray2[i])
for(j=0;j<temparray.length;j++){
console.log(temparray[j])
if(temparray2[i].id==temparray[j].parentid){
temparray2[i].children.push(temparray[j])
}
}
}
}
//Switch tampactif value and clean temp array
if(tempactif==1){
//console.log(temparray)
temparray2=[]
tempactif=2
}else{
// console.log(temparray2)
temparray=[]
tempactif=1
}
// }//en of else
}//end of lvl loop
console.log('count')
if(tempactif==1){
this.categories=temparray2
}else{
this.categories=temparray
}
}
},
Thanks !!!

Ok, i found a way arround, so here it is if anyone has the same issue :
buildTreeview3(){
var catdb=JSON.parse(JSON.stringify(this.$catdb))
var lvl = 0
var tempcat={}
var u
var i
var parentid
// count how many lvls max
for(i=0;i<catdb.length;i++){
if (catdb[i].level>lvl){lvl=catdb[i].level}
}
console.log('lvl : ',lvl)
// if only base lvl, no need to build treeview
if(lvl==0){
this.categories=this.$catdb
}
else{
for(u=lvl;u>0;u--){
//for each lvl starting from highest, go through the temp database catdb
for(i=0;i<catdb.length;i++){
if(catdb[i].level==u){
//When found a categorie from current lvl, found the position of its parent and add it to its child
parentid = catdb[i].parentid
let parentpos = catdb.map(function (e) {
return e.id;
}).indexOf(parentid);
tempcat=catdb[parentpos]
tempcat.children.push(catdb[i])
//remove the cat that has been added to childs from the temp db
//replace the parent by the parent with child
catdb.splice(i,1)
catdb.splice(parentpos,1,tempcat)
i=0
}
}
}
}//end of all (else if not just base lvl)
this.categories=catdb
},

Related

How to traverse back through the tree after reaching to the end in DFS- Javascript

This may sound very naive, but I'm working my path through algos and need help in figuring out the traversal using DFS.
I'm getting the response from a fetch () and storing the data in an array. and using Array.shift() to get the first node from the array, pass it to the url as an id and call for another fetch() to get data related to that id.
By doing this I do reach the end of one side, however I dont know how should I go back to the root and check if there are any more children.
here is code:
data={
id: "647634",
depth: 1,
data: ["node1","node2","node3"]
}
the data for every node call look like above.
function getData(id, explored) {
var self = this;
let explored = visited && visited.length>0 ? visited : new Array();
fetch("https://test.com/id", function(data){
//here im checking if its the end child:
if (data.end) {
var end =[];
end.push(data.end); // o/p: endId: "7287382"
}else {
let s = new Array();
data.forEach(function(n){
s.push(n);
})
var t = s.shift();
explored.push(t);
self.getData(t,explored)
}
});
}
any ideas?

How can I do ng-repeat with a firebase Array?

Context
In a Firebase DB I'm storing "events" and "users". Users can have favorite events, to manage them I only store the event's id in the favorite user's DB location. So to grab favorite events informations, I need to firstable grab the event id and then go to the DB events location, to collect all the datas I need.
Problem
I would like to store in an Array all the favorite events informations (each event would be an Object with inside it : "key" : "value"), to use that Array in my HTML view and print the informations. But it doesn't work the way I coded it... :(
// This ref is too grab favorite event id (in my case only 2) in the user DB location
var refUserFavoris = firebase.database().ref().child("users/"+user.uid+"/events/favoris");
$scope.favorisTmp = $firebaseArray(refUserFavoris);
// This shows one array, with two objects (wich are my two user's favorite events) wich include ids
console.log($scope.favorisTmp);
// This is to load the objects and with the foreEach, grab there ids to use them in the next ref call
$scope.favorisTmp.$loaded().then(function()
{
angular.forEach($scope.favorisTmp, function(favoris)
{
// This shows two lines : the id of each object
console.log(favoris.$id);
// Call a new ref to reach the event informations (in a different location of the DB) using the previous id
firebase.database().ref("events/"+favoris.$id).once('value').then(function(snapshot)
{
// Attempt to store events datas for each id I have (in my case, only two)
snapshot.forEach(function(favorisSnap)
{
var favSnap = favorisSnap.val();
// This shows a lot of "undefined" lines, wich I don't want. I would like two objects, with all informations inside
console.log(favSnap.nbPersonne);
// $scope.favorisF is an Array that I would like to use in a ng-repeat to print all datas for each event
// For now this doesn't show anything
$scope.favorisF = favSnap;
});
// If using favSnap out of the previous function, I got a "favSnap" is undifined error
console.log(favSnap);
});
});
});
<ion-item ng-repeat="f in favorisF" class="item-avatar">
{{f.nbPersonne}}
</ion-item>
EDIT 1 :
I tried a new way to have my data, but a new problem came, how to fill an Array inside a loop ? I've tried "push" and "$add" methods, but no one worked. Any ideas ?
var newFav = [];
var user;
user = firebase.auth().currentUser;
var refUserFavoris = firebase.database().ref().child("users/"+user.uid+"/events/favoris");
$scope.favorisTmp = $firebaseArray(refUserFavoris);
$scope.favorisTmp.$loaded().then(function()
{
angular.forEach($scope.favorisTmp, function(favoris)
{
console.log(favoris.$id);
var refFavoris = firebase.database().ref("events/"+favoris.$id);
refFavoris.on('value', function(snap)
{
//This is where I'm trying to fill "newFav" in each steps of the loop
newFav.push(snap.val());
console.log("Scope newFav vaut :", $scope.newFav);
});
});
});
I think you made a typo here.
var refUserFavoris = firebase.database().ref("events/favoris/"+favoris.$id).once('value')
Thanks a lot Abdel, I fixed my problem :
Here is the solution
$scope.newFav = [];
console.log($scope.newFav);
$scope.favorisTmp.$loaded().then(function()
{
angular.forEach($scope.favorisTmp, function(favoris)
{
console.log(favoris.$id);
var refFavoris = firebase.database().ref("events/"+favoris.$id);
refFavoris.on('value', function(snap)
{
$scope.newFav.push(snap.val());
console.log("Scope newFav vaut :", $scope.newFav);
});
});
});

Json cascading dropdown

I'm trying to set up a cascading dropdown using JSON data. I have it working somewhat but need some assistance getting the 2nd tier to work as intended. Currently it seems to be grabbing the number in the array.
Ideally for my 2nd tier I want to show the text in the dropdown as the option text, and I'd like to use the id field in the json as the value of the option.
var data = {
"Crime":[
{"id":"1","text":"Number of police"},
{ "id":"2","text":"Number of crimes"}
],
"Health":[
{"id":"3","text":"Number of doctors"},
{"id":"4","text":"Number of hospital visits"},
{"id":"5","text":"Number of nurses"}
],
}
I have a jsfiddle showing what I have so far.
Happy to use whatever combination of javascript/jquery works best.
The way you have used for..in seems to be incorrect. The question variable will not contain the entire value if the pointed collection (data[this.value], in this case) is not a simple array. Rather, it would contain the index of the first row, the second row and so on. I request you to read this for a more in-depth understanding :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
This line here
questionSel.options[questionSel.options.length] = new Option(question, question);
Must read this way
questionSel.options[questionSel.options.length] = new Option(
data[this.value][question].text,
data[this.value][question].id);
Here's an updated fiddle after this change has been made:
http://jsfiddle.net/tc1f3kup/2/
please try this
var data = {
"Crime":[
{"id":"1","text":"Number of police"},
{ "id":"2","text":"Number of crimes"}
],
"Health":[
{"id":"3","text":"Number of doctors"},
{"id":"4","text":"Number of hospital visits"},
{"id":"5","text":"Number of nurses"}
],
}
window.onload = function () {
var themeSel = document.getElementById("theme"),
questionSel = document.getElementById("questions");
for (var theme in data) {
themeSel.options[themeSel.options.length] = new Option(theme, theme);
}
themeSel.onchange = function () {
questionSel.length = 1; // remove all options bar first
if (this.selectedIndex < 1) return; // done
for(var i=0;i<data[this.value].length;i++)
{
questionSel.options[questionSel.options.length] = new Option(data[this.value][i].text, data[this.value][i].id);
}
}
}
working fiddle
http://jsfiddle.net/tc1f3kup/3/

angular check if item exists in scope (array) already

I'm trying to check if I have something in an array already before adding - so that I cannot add the same type more than once. I am checking the model of the drop down I am selecting from against the array I am storing everything in (there is a slight difference in that the model stores the id as id and the array as skillId).
I am basically just trying to look through the array and see if the id matches - and if it does do not add the item to the array. Here is the code.
$scope.saveSkill = function() {
//send skill to get path, then add to skills array
console.log($scope.pathArray);
console.log($scope.scope5.id);
var skillCheck = true;
//check if exists aready
for(i=0;i<$scope.pathArray.length;i++){
if($scope.pathArray[i].skillId = $scope.scope5.id ){
console.log("Cannot add same skill more than once");
skillCheck = false;
}
}
if(skillCheck){
$http({
method: 'GET',
url: '/findPathScopeToSkill/' + $scope.scope5.id + "/1"
})
.success(function(data){
angular.forEach(data.paths, function(index) {
$scope.pathArray.push(index);
});
});
}
};
Just as a quick reference - pathArray is where the items get pushed into and where I do not want to have doubles - so I am checking the current id vs the id's inside the array (only difference is they are .skillId's)
I can add one, then can't add the same one again BUT I also can't add any after that. Can't seem to figure out what I am doing wrong here. Any help would be greatly appreciated. Thanks!

Loop through all Mongo collections and execute query

First of, I'm quite new to mongodb. Here's my question I've not been able to find a solution to.
Let's say I have 3 different collections.
mongos> show collections
collectionA
collectionB
collectionC
I want to create a script that iterates over all collections ind this database and find the last inserted timestamp in each of these collections. Here's what works inside mongos.
var last_element = db.collectionA.find().sort({_id:-1}).limit(1);
printjson(last_element.next()._id.getTimestamp());
ISODate("2014-08-28T06:45:47Z")
1. Problem (Iterate over all collections)
Is there any possibility to to sth. like.
var my_collections = show collections;
my_collections.forEach(function(current_collection){
print(current_collection);
});
Problem here, the assignment for my_collections does not work.
I get SyntaxError: Unexpected identifier. Do I need to quote the 'show' statement ? Is it even possible ?
2. Problem (storing collection in js var)
I can workaround Problem 1 by doing this:
var my_collections = ["collectionA", "collectionB", "collectionC"];
my_collections.forEach(function(current_collection){
var last_element = db.current_collection.find().sort({_id:-1}).limit(1);
print(current_collection);
printjson(last_element.next()._id.getTimestamp());
});
The last_element.next() produces the following error:
error hasNext: false at src/mongo/shell/query.js:124
It seems that last_element isn't saved correctly.
Any suggestions on what I'm doing wrong??
UPDATE
Neils answer lead me to this solution. In addition to his code I had to check if the function getTimestamp really exist. For some 'virtual' collections there seem to be no _id property.
db.getCollectionNames().forEach(function(collname) {
var last_element = db[collname].find().sort({_id:-1}).limit(1);
if(last_element.hasNext()){
var next = last_element.next();
if(next._id !== undefined && typeof next._id.getTimestamp == 'function'){
printjson(collname + " >> "+next._id.getTimestamp());
}else{
print(collname + " undefined!! (getTimestamp N/A)")
}
}
});
There is the db.getCollectionNames() helper method that does this for you. You can then implement your code:
db.getCollectionNames().forEach(function(collname) {
// find the last item in a collection
var last_element = db[collname].find().sort({_id:-1}).limit(1);
// check that it's not empty
if (last_element.hasNext()) {
// print its timestamp
printjson(last_element.next()._id.getTimestamp());
}
})
You probably also want a .hasNext() check in there to cater for possible empty collections.
Rename the collection name present in all the records using the following script:
db = db.getSiblingDB("admin");
dbs = db.runCommand({ "listDatabases": 1 }).databases;
dbs.forEach(function(database) {
db = db.getSiblingDB(database.name);
db.currentname.renameCollection("newname");
});

Categories