NodeJS - how to send a variable to nested callbacks? (MongoDB find queries) - javascript

I want to use result set of a find query in another result set. I couldn't explain this situation in english very well. I will try to use some code.
People.find( { name: 'John'}, function( error, allJohns ){
for( var i in allJohns ){
var currentJohn = allJohns[i];
Animals.find( { name: allJohns[i].petName }, allJohnsPets ){
var t = 1;
for( var j in allJohnsPets ){
console.log( "PET NUMBER ", t, " = " currentJohn.name, currentJohn.surname, allJohnsPets[j].name );
t++;
}
}
}
});
Firstly, I get all people with find who are named John. Then I take those people as allJohns.
Secondly, I get all pets of every Johns one by one in different find queries.
In second callback, I get every pet one by one again. But when I want to display which John is their owners, I always got same John.
So, the question is: how can I send every John separately to the second nested callback and they will be together as real owners and pets.
I need to copy every John but I have no idea how can I do this.

Javascript has no block scope, only function scope. Instead of for .. in .., using forEach will create a new scope for each loop:
People.find( { name: 'John'}, function( error, allJohns ){
allJohns.forEach(function(currentJohn) {
Animals.find( { name: currentJohn.petName }, function(err, allJohnsPets) {
allJohnsPets.forEach(function(pet, t) {
console.log( "PET NUMBER ", t + 1, " = ", currentJohn.name, currentJohn.surname, pet.name );
});
});
});
});

You have to give more concentration on asynchronous nature.
People.find( { name: 'John'}, function( error, allJohns ){
for( var i=0; i<allJohns.length; i++ ){
(function(currJohn){
var currentJohn = currJohn;
Animals.find( { name: currentJohn.petName }, function(error, allJohnsPets){
for(var j=0; j<allJohnsPets.length; j++){
console.log( "PET NUMBER ", (j+1), " = " currentJohn.name, currentJohn.surname, allJohnsPets[j].name );
}
})
})(allJohns[i]);
}
});

Related

How to get values in Json Array and use each of them separately

I have a JSON and I Want to separate each field of that in array part and then I want to use of each field separately and put them in separate array.
for example I have two part in my array and I want to divide the first part too room 1 and second part in room 2 .
I have to send Json to my second page with format room1 and room 2. and I do not know how can I do this
my json is like this right now :
"rooms": [
{
"adultcount": "1",
"childcount": "1,1"
},
{
"adultcount": "1",
"childcountandage": "0 "
}
]
but I want to change it like this :
"rooms": [
{
"rooms1": {
"adultcount": "1",
"childcount": "1,1"
}
},
{
"rooms2": {
"adultcount": "2",
"childcount": "10,1"
}
}
]
then I need to use them.
how can I do this with jquery ?
there is no need to change the json code I just wrote the sample the new json to define better.
here is my code :
$( document ).ready(function() {
var research={"rooms":[{ "adultcount":"1","childcount":"1,1" },{ "adultcount":"1","childcountandage":"0 " }] }
var adultcount = research.rooms[0].adultcount;
var childcount = research.rooms[0].childcount;
});
Since you have an array that you want to make into an object and the property name seems to be the index inside the array, you can use a basic array.reduce:
var rooms = [
{ "adultcount":"1", "childcount":"1,1" },
{ "adultcount":"2", "childcount":"10,1" }
];
var roomsMap = rooms.reduce( function( map, room, index ) {
map[ 'room' + ( index + 1 ) ] = room;
return map;
}, {} );
var otherRoomsMap = rooms.map( function( room, index ) {
var wrapper = {};
wrapper[ 'room' + ( index + 1 ) ] = room;
return wrapper;
} );
console.log( roomsMap );
console.log( otherRoomsMap );
edit:
I have added the other example of keeping the array and just wrapping the objects isnide another object, but I have no idea what advantage that would give over the original array.
You can access your json array using loop
$.each(research, function (key, value) {
var adultcount = value.adultcount;
var childcount = value.childcount;
console.log("Adult count is:"+value.adultcount);
console.log("Child count is:"+value.childcount);
});
Try this:
var research={"rooms":[{ "adultcount":"1","childcount":"1,1" },{"adultcount":"1","childcountandage":"0 " }] };
var newResearch = {"rooms": []};
research.rooms.forEach(function(r) {
newResearch.rooms.push({"room1": r[0], "room2": r[1]});
});
console.log(newResearch);

Javascript array parsing

var usersRows = [];
connection.query('SELECT * from users', function(err, rows, fields) {
if (!err) {
rows.forEach(function(row) {
usersRows.push(row);
});
console.log(usersRows);
}
else {
console.log('Error while performing Query.' + err);
}
});
It returned to me:
var usersRows = [ [ RowDataPacket { id: 1, name: 'sall brwon', number: '+99999999\r\n' } ] ];
I need to parse this and remove rowdatapacket; I need result like this:
userRows = { id: 1, name: 'my name is', number: '+999999\r\n' };
If you need to get rid of RowDataPacket's array and save it in yours you can also use this:
usersRows = JSON.parse(JSON.stringify(results));
Have you tried
userRows = RowDataPacket;
You might want to try JSON.stringify(rows)
Was unable to understand and implement the accepted the answer.
Hence, tried the long way out according the results I was getting.
Am using "mysql": "2.13.0" and saw that the this library returned array of array out of which:
Index 0 had array of RowDataPackets
Index 1 had other mysql related information.
Please find the code below:
var userDataList = [];
//Get only the rowdatapackets array which is at position 0
var usersRows = data[0];
//Loop around the data and parse as required
for (var i = 0; i < usersRows.length; i++) {
var userData = {};
//Parse the data if required else just
userData.name = userRows.firstName + userRows.lastName;
userDataList.push(userData);
}
If no parsing is required and you just want the data as is, you could use the solution like mentioned in link How do I loop through or enumerate a JavaScript object?
Have not tried it but could be tweaked and worked out.
There should be simpler way to do it but as a novice I found the above way server the purpose. Do comment in case of better solution.
RowDataPacket is the class name of the object that contains the fields.
The console.log() result [ [ RowDataPacket { id: 1, name: 'sall brwon', number: '+99999999\r\n' } ] ] should be read as "an array of one item, containing and array of one item, containing an object of class RowDataPacket with fields id, name, and number"

Search array for string - returning -1

I've been reading lots of StackOverflow answers which tell me that, in Javascript, the best way to search an array for a particular string is use indexOf(). I have been trying to make this work for a while now, and I need some help with it.
I am making a shop in a text-adventure game. These are the values I am using:
The array shopCosts:
shopCosts = [20, 25];
The array shopItems:
shopItems = [["Sword", "Shield"]];
I dynamically create radiobuttons by looping through shopItems:
for(var i = 0; i < array.length; i++)
{
// Create the list item:
var item = document.createElement('li');
// Set its contents:
item.appendChild(document.createTextNode(array[i] + " - " + shopCosts[i] + " Gold"));
// Add it to the list:
list.appendChild(item);
var label = document.createElement("label");
var radio = document.createElement("input");
var text = document.createTextNode(array[i]);
radio.type = "radio";
radio.name = "shop";
radio.value = array[i];
radio.onclick = function () { addValue(this.getAttribute("value"), shopCosts, shopItems) }
label.appendChild(radio);
label.appendChild(text);
document.body.appendChild(label);
}
This is the part in question:
radio.onclick = function () { addValue(this.getAttribute("value"), shopCosts, shopItems) }
My logic was basically to assign values to each dynamically created radiobutton, and if one was pressed, get the value (so, the name of the item you wanted to buy) and then search shopItems for that particular string for the index value. Once I had that, I would look in the same "parallel" list shopCosts to find the price.
I used console.log() to see what variables were in play. When I clicked on the radio button, this function is called:
function addValue(nameOfItem, shopCosts, shopItems)
{
var positionOfShopItem = shopItems.indexOf(nameOfItem);
console.log(positionOfShopItem);
console..log(nameOfItem);
console.log(shopItems);
}
Surely, the console.log() would return the position of the named item? To prove to myself I'm not going crazy, here's what the Dev Tools say:
-1
Sword
[Array[2]]
0: "Sword"
1: "Shield"
Sword is clearly in the array, in position 0, so why is indexOf() returning -1?
Any help appreciated!
As I alluded to in my comment, its because shopItems does not contain an array of strings, it contains a single element, where that one element is an array of strings. I suspect your code would work just fine if you removed the extra square braces
var shopItems = ["Sword", "Shield"];
I realize you've already fixed the bug, but I urge you to consider a different approach to the problem. These two principles will not only solve the problem in a cleaner way, but they also give you a new way to think about similar problems in the future:
Never use parallel arrays. Use a single array of objects instead.
In your main loop that appends the items, put the main body of the loop in a function.
If you follow these two ideas you gain several benefits. The code becomes much more straightforward, easier to maintain, and you don't have to do any array lookups at all!
Each shop item is packaged up as a single object in the array, like this:
var shopItems = [
{ name: 'Sword', cost: 20 },
{ name: 'Shield', cost: 25 }
];
So if you have a reference to the shop item as a whole, say in a variable called shopItem, then you automatically have all of its properties available: shopItem.name and shopItem.cost. This lets you also easily add more bits of data to a shop item, e.g.
var shopItems = [
{ name: 'Sword', cost: 20, dangerous: true },
{ name: 'Shield', cost: 25, dangerous: false }
];
and now shopItem.dangerous will give you the appropriate value. All without any array lookups.
Making the main loop body into a function adds a further benefit: Inside that function, its parameters and local variables are preserved each time you call the function (this is called a closure). So now you don't even have to fetch the list item value and look it up - you already have the appropriate shopItem available in the code.
Putting this together, the code might look like this:
var shopItems = [
{ name: 'Sword', cost: 20, dangerous: true },
{ name: 'Shield', cost: 25, dangerous: false }
];
var list = document.getElementById( 'list' );
for( var i = 0; i < shopItems.length; ++i ) {
appendShopItem( shopItems[i] );
}
// Alternatively, you could use .forEach() instead of the for loop.
// This will work in all browsers except very old versions of IE:
// shopItems.forEach( appendShopItem );
function appendShopItem( shopItem ) {
// Create the list item:
var item = document.createElement( 'li' );
// Set its contents:
item.appendChild( document.createTextNode(
shopItem.name + ' - ' + shopItem.cost + ' Gold'
) );
// Add it to the list:
list.appendChild( item );
var label = document.createElement( 'label' );
var radio = document.createElement( 'input' );
var text = document.createTextNode( shopItem.name );
radio.type = 'radio';
radio.name = 'shop';
radio.value = shopItem.name;
radio.onclick = function () {
addValue( shopItem );
};
label.appendChild( radio );
label.appendChild( text );
document.body.appendChild( label );
}
function addValue( shopItem ) {
console.log( shopItem );
alert(
shopItem.name +
' costs ' + shopItem.cost + ' and is ' +
( shopItem.dangerous ? 'dangerous' : 'not dangerous' )
);
}
New fiddle (with a tip of the hat to Jamiec for the original fiddle)
As you can see, this makes the code much easier to understand. If you have a shopItem, you automatically have its name, cost, and any other property you want to add. And most importantly, you never have to keep track of putting your values in the same order in two, three, or even more different arrays.
shopItems is an Array of Arrays. The 0 index of shopItems contains another array which contains:
["Sword", "Shield"]
So when you are trying to find the "Sword" item or "Shield" Item inside of shopItems it is returning -1 because it cannot find either inside of the array.
Change
shopItems = [["Sword", "Shield"]];
To
shopItems = ["Sword", "Shield"];
And that will fix your issue.
I've fixed it!
Removing the double square brackets resulted in this mess. So, as a workaround, I simply added [0] to var positionOfShopItem = shopItems.indexOf(nameOfItem); to get var positionOfShopItem = shopItems[0].indexOf(nameOfItem);
Thanks for everyone's help.

Loop Through JSON, Insert Key/Value Between Objects?

UPDATE - Thanks for all the great answers and incredibly fast response. I've learned a great deal from the suggested solutions. I ultimately chose the answer I did because the outcome was exactly as I asked, and I was able to get it working in my application with minimal effort - including the search function. This site is an invaluable resource for developers.
Probably a simple task, but I can't seem to get this working nor find anything on Google. I am a Javascript novice and complex JSON confuses the hell out of me. What I am trying to do is make a PhoneGap Application (Phone Directory) for our company. I'll try to explain my reasoning and illustrate my attempts below.
I have JSON data of all of our employees in the following format:
[
{
"id":"1",
"firstname":"John",
"lastname":"Apple",
"jobtitle":"Engineer"
},
{
"id":"2",
"firstname":"Mark",
"lastname":"Banana",
"jobtitle":"Artist"
},
... and so on
]
The mobile framework (Framework 7) that I am using offers a "Virtual List" solution which I need to take advantage of as our directory is fairly large. The virtual list requires you to know the exact height of each list item, however, you can use a function to set a dynamic height.
What I am trying to do is create "headers" for the alphabetical listing based on their last name. The JSON data would have to be restructured as such:
[
{
"title":"A"
},
{
"id":"1",
"firstname":"John",
"lastname":"Apple",
"jobtitle":"Engineer"
},
{
"title":"B"
},
{
"id":"2",
"firstname":"Mark",
"lastname":"Banana",
"jobtitle":"Artist"
},
... and so on
]
I've been able to add key/value pairs to existing objects in the data using a for loop:
var letter, newLetter;
for(var i = 0; i < data.length; i++) {
newLetter = data[i].lastname.charAt(0);
if(letter != newLetter) {
letter = newLetter
data[i].title = letter;
}
}
This solution changes the JSON, thus outputting a title bar that is connected to the list item (the virtual list only accepts ONE <li></li> so the header bar is a div inside that bar):
{
"id":"1",
"firstname":"John",
"lastname":"Apple",
"jobtitle":"Engineer",
"title":"A"
},
{
"id":"1",
"firstname":"Mike",
"lastname":"Apricot",
"jobtitle":"Engineer",
"title":""
}
This solution worked until I tried implementing a search function to the listing. When I search, it works as expected but looks broken as the header titles ("A", "B", etc...) are connected to the list items that start the particular alphabetical section. For this reason, I need to be able to separate the titles from the existing elements and use them for the dynamic height / exclude from search results.
The question: How can I do a for loop that inserts [prepends] a NEW object (title:letter) at the start of a new letter grouping? If there is a better way, please enlighten me. As I mentioned, I am a JS novice and I'd love to become more efficient programming web applications.
var items = [
{ "lastname":"Apple" },
{ "lastname":"Banana" },
{ "lastname":"Box" },
{ "lastname":"Bump" },
{ "lastname":"Can" },
{ "lastname":"Switch" }
];
var lastC = null; //holds current title
var updated = []; //where the updated array will live
for( var i=0;i<items.length;i++) {
var val = items[i]; //get current item
var firstLetter = val.lastname.substr(0,1); //grab first letter
if (firstLetter!==lastC) { //if current title does not match first letter than add new title
updated.push({title:firstLetter}); //push title
lastC = firstLetter; //update heading
}
updated.push(val); //push current index
}
console.log(updated);
Well right now you have an array of objects - prefixing the title as its own object may be a bit confusing - a better structure may be:
[
{
title: "A",
contacts: [
{
"id":"1",
"firstname":"John",
"lastname":"Apple",
"jobtitle":"Engineer",
"title":"A"
}
]
Given your current structure, you could loop and push:
var nameIndexMap = {};
var newContactStructure = [];
for (var i = 0; i < data.length; i++) {
var letter = data[i].lastname.charAt(0);
if (nameIndexMap.hasOwnProperty(letter)) {
//push to existing
newContactStructure[nameIndexMap[letter]].contacts.push(data[i])
} else {
//Create new
nameIndexMap[letter] = newContactStructure.length;
newContactStructure.push({
title: letter,
contacts: [
data[i]
]
});
}
}
newContactStructure will now contain your sorted data.
Demo: http://jsfiddle.net/7s50k104/
Simple for loop with Array.prototype.splice will do the trick:
for (var i = 0; i < data.length; i++) {
if (i == 0 || data[i-1].lastname[0] !== data[i].lastname[0]) {
data.splice(i, 0, {title: data[i].lastname[0]});
i++;
}
}
Demo. Check the demo below.
var data = [
{"lastname":"Apple"},
{"lastname":"Banana"},
{"lastname":"Bob"},
{"lastname":"Car"},
{"lastname":"Christ"},
{"lastname":"Dart"},
{"lastname":"Dog"}
];
for (var i = 0; i < data.length; i++) {
if (i == 0 || data[i-1].lastname[0] !== data[i].lastname[0]) {
data.splice(i, 0, {title: data[i].lastname[0]});
i++;
}
}
alert(JSON.stringify( data, null, 4 ));

JavaScript Multi Dimentional Array

I have created a multidimensional array for a jobs feed like so:
var jobs = [
["JOB222" , "Painter"],
["JOB333" , "Teacher"],
["JOB444" , "Delivery Driver"],
];
I can access the array using the index number
alert( jobs[2][1] ); // Alerts Delivery Driver
If I set the reference number manually, I can loop through the array to find a match.
var viewingJobRef = "JOB333";
for (var i=0;i<jobs.length;i++) {
if (jobs[i][0] == viewingJobRef) {
alert(jobs[i][1]); // This will alert Teacher
}
}
So my question is, is it possible to access the array directly and not use a loop?
var viewingJobRef = "JOB333";
alert( jobs[viewingJobRef][1] ); // I want this to alert Teacher
Firefox error console says:
jobs[viewingJobRef]is undefined, how do I do it?
You want to use objects:
var jobs = {
"JOB222" : "Painter",
"JOB333" : "Teacher",
"JOB444" : "Delivery Driver"
};
Access like this :
var viewingJobRef = "JOB333";
alert( jobs[viewingJobRef] );
OR
alert( jobs["JOB333"] );
OR
alert( jobs.JOB333 );
You may use objects:
var jobs = {
"JOB222": "Painter",
"JOB333": "Teacher",
"JOB444": "Delivery Driver"
};
And loop with:
for ( var i in jobs ) {...}
Or access directly like:
alert( jobs.JOB333 );

Categories

Resources