I have a collection of data like this(for example) :
{
name : "john" ,
_id : "0"
},
{
name : "Richard" ,
parent_id : "0" ,
_id : "1"
},
{
name : "Kevin" ,
parent_id : "0" ,
_id : "2"
},
{
name : "William" ,
parent_id : "1" ,
_id : "3"
},
{
name : "George" ,
parent_id : "3" ,
_id : "4"
}
I'm trying to write a function to receive an _id and return all children in any depth of this node, for example for _id = 0 I need something like this :
[
{
name : "Richard" ,
parent_id : "0" ,
depth : "1" ,
_id : "1"
},
{
name : "Kevin" ,
parent_id : "0" ,
depth : "1" ,
_id : "2"
},
{
name : "William" ,
parent_id : "1" ,
depth : "2" ,
_id : "3"
},
{
name : "George" ,
parent_id : "3" ,
depth : "3" ,
_id : "4"
}
]
I write several recursive functions to iterate on my mongodb docs but the main problem is I can't handle callbacks (asynchronous) and don't know when and how can I end the recursive function.
How can I do this with mongodb and node.js?
Any idea can be useful ,thanks.
There is a 2 famous algorithm that you can use in order to achive your goal
BFS(Breath First search) and DFS(Depth First Search).
For this problem BFS is better than DFS because you can trace your tree in O(logn)
You can use DFS too but you have to implement it in recursive way and running time will be O(n) and because your are coding in node js you have to implement it in a asynchronous and it could be a little hard to implement it.
In order to implement BFS algorithm you have to use asynchronous while loop because you have to have mongo query in your while loop and if you use normal javascript your BFS won't work because we are talking about node js not php!!!
So first this is asynchronous while loop that I use in my BFS code
function asyncLoop(iterations, func, callback ,foo) {
var done = false;
var loop = {
next: function() {
if (done) {
return;
}
if (iterations) {
func(loop);
} else {
done = true;
if(callback) callback(foo);
}
},
isEnd : function(){
return done ;
} ,
refresh : function(it){
iterations = it ;
},
break: function() {
done = true;
callback();
}
};
loop.next();
return loop;
}
And this is BFS algorithm node js code:
function bfs (_id ,callback){
_id = String(_id);
var q = [] ,res = [] ;
db.tasks.findOne({ _id : _id }).lean().exec(function(err,root){
root.depth = 0 ;
q.push(root);
asyncLoop(q.length ,function(loop){
res.push(q[0]);
db.tasks.find({ _parent : q[0]._id }).lean().exec(function(err,new_nodes){
if(err) console.log(err);
else {
var d = q[0].depth ;
q.shift();
loop.refresh(new_nodes.length + q.length);
if(new_nodes.length > 0){
new_nodes.forEach(function(new_node){
new_node.depth = d+1 ;
q.push(new_node);
});
}
loop.next();
}
});
},function(){ callback(res) });
});
}
Note:I also save depth of each query so you can have depth of each query and know where this query is in tree.
Related
This is 'product.js' file, and when ever I am calling the api '/achaar/products/1', the value of val is giving empty in console. Other api calls like '/achaar/products' is working fine, but on calling with id this is not working.
const express = require('express')
const router = express.Router();
const json_data = require('./test_data');
const cons = require('./constants')
/*
url is : /achaar/products
replace test data with database datas
*/
router.get(cons.URLS.all_product,(req,res) => {
res.json(json_data)
})
router.get(cons.URLS.all_product+'/:id',(req,res) => {
console.log(req.params.id)
var val = json_data.achaar.filter(function (x) { return x.id === req.params.id })
console.log(val)
})
module.exports = router
Here is my test_data.js file
{
"achaar" : [
{
"id" : 0,
"name" : "Ginger Tangi",
"cost" : 2000
},
{
"id" : 1,
"name" : "Mango Khatta",
"cost" : 1200
},
{
"id" : 2,
"name" : "Gaas Dhari",
"cost" : 3000
},
{
"id" : 3,
"name" : "Cream Tangy",
"cost" : 1000
}
]
}
Because you use === and it was check value and type is equal
You should convert req.params.id to number because id of data is number.
I am trying to read the data from firebase database, and display the same in a webpage.
My database structure is as below -
If you see the image, i am able to read the "UserData" using the below code -
firebase.initializeApp(config);
var database = firebase.database();
var ref = database.ref('UserData');
ref.once('value', gotData1, errData);
function gotData1(data){
//console.log(data.val());
var usrData = data.val();
var keys = Object.keys(usrData);
//console.log(keys);
for (var i = 0; i< keys.length; i++){
var k = keys[i];
var id = usrData[k].AssignedID;
var name = usrData[k].Name;
$(document).ready(function() {
var $formrow = '<tr><td>'+id+'</td><td>'+name+'</td></tr>';
$('#userInfo').append($formrow);
});
}
}
In the highlighted part of the image, you can see keys with values 196214, 196215, 196216
Now, I need to fetch the values for "One, Count" by matching the key values with available AssignedID.
How can i achieve the same?
Update, JSON as text -
{
"app_url" : "https://app_name?ls=1&mt=8",
"UserData" : {
"HNpTPoCiAYMZEeVOs01ncfGBj6X2" : {
"Name" : "Arunima Vj"
"Email" : "asd#upp.com",
"AssignedID" : 196214
},
"VXU2tdGdzZX90PJa9mpEL3zAiZo2" : {
"Name" : "Lakshman Medicherla"
"Email" : "asd#upp.com",
"AssignedID" : 196215
},
"dFlwtqDNrja2RkOySVtW106IQP62" : {
"Name" : "Prashanth Sripathi"
"Email" : "asd#upp.com",
"AssignedID" : 196216
}
}
"teams" : {
"196214" : {
"1105" : {
"One" : 7619,
"count" : 24
},
"1379" : {
"Two" : 7145,
"count" : 21
}
},
"196215" : {
"1111" : {
"One" : 7779,
"count" : 20
},
"1508" : {
"Two" : 1176,
"count" : 21
}
},
"196216" : {
"1106" : {
"One" : 7845,
"count" : 22
},
"1509" : {
"Two" : 1156,
"count" : 26
}
}
}
}
Your data structure is quite nested, which makes the code more difficult to read. But this navigates the structure generically in the minimum code I could come up with:
var ref = firebase.database().ref("/42824688");
ref.child("UserData").once('value', gotUserData);
function gotUserData(snapshot){
snapshot.forEach(userSnapshot => {
var k = userSnapshot.key;
var id = userSnapshot.val().AssignedID;
var name = userSnapshot.val().Name;
ref.child("teams").child(id).once("value", teamsSnapshot => {
teamsSnapshot.forEach(teamSnapshot => {
var teamKey = teamSnapshot.key;
teamSnapshot.forEach(teamProp => {
var prop = teamProp.key;
var val = teamProp.val();
console.log(k+" "+name+" "+id+": "+teamKey+", "+prop+"="+val);
});
});
});
})
}
So for each user, this loads the teams data for that user and then loops over the teamsSnapshot to get each teamSnapshot and then loops over that to get each team property.
Working jsbin: http://jsbin.com/noziri/edit?html,js,console
Goodmorning
I am trying to match certain fields over a dataset. The dataset contains records like:
{
"token" : "17e0d95f2e2112443cfb09970ae9140e",
"answers" : {
"Yourname" : "Marco",
"youremail" : "marco#me.nl",
"recemail" : "sonja#me.nl"
}
},
{
"token" : "cf5ae65b05249dc6b2a0c99c4cf9688e",
"answers" : {
"yourname" : "Sonja",
"youremail" : "sonja#me.nl",
"recemail" : "marco#me.nl"
}
}
In this case, it should match the two because the recemail (recipients email) matches someone else's email address. And vice versa.
What I am trying to find is how to find these two records (in a larger dataset with more of these matches).
So, Marco's recemail should find Sonja's youremail and these two matches should then be made available to save into another collection, but that's not the important part here.
hope someone can help me with this query
Thanks!
The following code will return an array of 2-entry arrays. Each 2-entry array is made of the sender email and the recipient email. Each pair will appear only once. In other words, you'll get ["marco#me.nl", "sonja#me.nl"] but not ["sonja#me.nl", "marco#me.nl"].
var list = [{
"token" : "17e0d95f2e2112443cfb09970ae9140e",
"answers" : {
"Yourname" : "Marco",
"youremail": "marco#me.nl",
"recemail" : "sonja#me.nl" }
}, {
"token" : "cf5ae65b05249dc6b2a0c99c4cf9688e",
"answers" : {
"yourname" : "Sonja",
"youremail": "sonja#me.nl",
"recemail" : "marco#me.nl" }
}, {
"token" : "fe2c2740e083dfe02cc7e96520a0e079",
"answers" : {
"yourname" : "Joe",
"youremail": "joe#foo.com",
"recemail" : "mike#bar.com" }
}
];
var res = [], sz = list.length;
list.forEach(function(obj, pos) {
for(var i = pos + 1; i < sz; i++) {
if(
list[i].answers.youremail == obj.answers.recemail &&
list[i].answers.recemail == obj.answers.youremail
) {
res.push([ obj.answers.youremail, obj.answers.recemail ]);
}
}
});
console.log(res);
i am newbie to nodejs/javascript and trying to pass a value from a function.
Below is my request.on function ( i need to get favoriteStn value and pass it on while building the JSON array)
response.on('end', function () {
str = JSON.parse(str);
var summariesJSON = str[0].summaries
var resToSend = [];
for(var i in summariesJSON) {
var item = summariesJSON[i];
var favoriteStn = findifFavorite (usernameFrmQuery,item.device_id,function(value){
favoriteStn = value;
});
resToSend.push({
"lat" : item.lat,
"lng" : item.ln,
"count" : item.count,
"status" : item.status,
"id" : item.id,
"name" : item.name,
"address" : item.address,
"favoriteStn" : favoriteStn,
"fav_count" : findFavCount
});
}
res.send(resToSend);
});
function findifFavorite (username,stationId,cb) {
var options = {
};
ddb.getItem(chgStationfavorite, username, String(stationId), options, function(err, getitemRes, cap) {
if (err) {
cb("Failure" + err);
} else if(typeof(getitemRes) != 'undefined'){
cb("Y");
}
else {
cb("N");
}
});
}
issue is i dont get anything created for favoriteStn, i know it is getting into the function and providing values as i can see it thru console.log
can you help me on how i need to use callback and get it working?
you have to consider everything in node.js is asynchronous.
in your case findifFavorite execution time is taking more time and the value is not available for the array.
this is how you can fix your code, you have to move the resToSend array in the callback function.
Start reading more about promises
https://github.com/petkaantonov/bluebird
so you will not get stuck in callback hell.
var favoriteStn = findifFavorite (usernameFrmQuery,item.device_id,function(value){
favoriteStn = value;
resToSend.push({
"lat" : item.lat,
"lng" : item.ln,
"count" : item.count,
"status" : item.status,
"id" : item.id,
"name" : item.name,
"address" : item.address,
"favoriteStn" : favoriteStn,
"fav_count" : findFavCount
});
res.send(resToSend);
});
I have a problem, may you help me!
I have a json array:
"category" : [
{
id: 1,
product: [{id : product_1, type : ball}]
},
{
id : 2,
product :[{id : product_2, type : pen}]
}
]
My problem is: if i have a link such as: http://test/category/1 then , How can I do to get product information by category with id = 1 ?
Thanks for any suggestion :)
This is a way to do it in one line and without using for:
function filterById(jsonObject, id) {return jsonObject.filter(function(jsonObject) {return (jsonObject['id'] == id);})[0];}
Then if you want to get, for example, the object with id=2, you just use:
var selectedObject = filterById(yourJson['category'], 2);
And then selectedObject will get this value, as per your example:
{
id : 2,
product :[{id : product_2, type : pen}]
}
There is a downside: Old browsers, such as IE8, don't support filter() so you need to add this polyfill code for old browser compatibility:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#Polyfill
Assuming your data structure looks like this:
var data = {
"category" : [
{
id: 1,
product: [{id : product_1, type : ball}]
},
{
id : 2,
product :[{id : product_2, type : pen}]
}
]
}
Then, you can find the item in the category array with id == 1 by searching through the array like this:
function findId(data, idToLookFor) {
var categoryArray = data.category;
for (var i = 0; i < categoryArray.length; i++) {
if (categoryArray[i].id == idToLookFor) {
return(categoryArray[i].product);
}
}
}
var item = findId(data, 1);
// item.id, item.type
If you save your array of categories in categories JS variable, you can filter this array based on simple JavaScript (with no jQuery) like that:
var result = categories.filter(function(element){
if (element.id == 2){
return true;
} else {
return false;
}
});
and then in result[0].product you will have array of products that are within specific category.
See this jsfiddle for a proof.
PS. filter() method is not available in all browsers, you may need to apply some code that will make it available if needed and not found. Here is some article on Mozilla Developers Network on the details of filter() and the code you need to make it work on old browsers: MDN: filter().
I think the OP wants to retrieve corresponding data from url.
So the first step is map the url to identifier
var urlParts = window.location.href.split(/\//)
//window.location.href = http://domain.com/category/1
// urlParts = ['http:', '', 'domain.com', 'category', '1']
var id = urlParts.pop();
var category = urlParts.pop();
Then you retrive the data from JSON string with JSON.parse:
var data = JSON.parse('{"category" : [{"id": 1, "product": [{"id" : "product_1", "type" : "ball"}] }, {"id" : 2, "product" :[{"id" : "product_2", "type" : "pen"}] } ]}');
//The data structure
// {"category" : [
// {"id": 1, "product" :
// [
// {"id" : "product_1", "type" : "ball"}
// ]},
// {"id" : 2, "product" :
// [
// {"id" : "product_2", "type" : "pen"}
// ]}
// ]}
At last, you can retrive the data similar #jfriend00's post with id and category
function findId(data, idToLookFor) {
var categoryArray = data.category;
for (var i = 0; i < categoryArray.length; i++) {
if (categoryArray[i].id == idToLookFor) {
return(categoryArray[i].product);
}
}
}
var item = findId(data.category, id);
// item.id, item.type
You might have found the answer, but if you haven't you can simply use the logical OR (||) operator.
In your case, you can use jQuery's ajax() method. To grab your product based on ids just use the below simple logic:
var prodID1 = 1, prodID2 = 2;
if(this.id == prodID || this.id == prodID2) {
//write your JSON data, etc.
//push to array, etc.
}
"category" : [
{
id: 1,
product: [{id : product_1, type : ball}]
},
{
id : 2,
product :[{id : product_2, type : pen}]
}
]
In this scenario I recommend, that you get the array from the Json response using the key. For example if your json response name is : "data" then do "data.category" which will give you an array to loop through.
Then
const allProducts = data.category;
allProducts .forEach((element) => {
//here id is your own id by which you want to compare against the json object
if (element.id == id) {
response.status(200).json(element)
//or you can return this element and capture it for any other operation you desire to do
}
});