I started using Couchbase for a new project of mine and I hope you can help me solve a problem.
I have two types of documents in my bucket. For example:
{
"id": "A1",
"name": "Name of A",
"type": "A"
}
and
{
"id": "B1",
"name": "Name of B",
"type": "B",
"parentIDs": ["A1", "A4", "A5"]
}
I want to create a view with the following result:
{
"id": "A1",
"name": "Name of A",
"type": "A",
"children": [
{JSON document of child 1},
{JSON document of child 2},
{JSON document of child 3}
]
}
I started to write a function and a nested one, which should iterate through all documents but I must surrender... Can you help me?
function (doc, meta)
{
if(doc.type == "A")
{
emit(doc, GetAllSites(doc));
}
function GetAllSites(doc)
{
var sites = [];
for(var i = 0; i < doc.length; i++)
{
sites.push(doc.id);
}
return sites;
}
}
Thanks
-----------------UPDATE-----------------
I solved my problem this way:
// map function
function (doc, meta)
{
emit(meta.id, doc);
}
// reduce function
function (key, values, rereduce)
{
var result = [];
for(var i = 0; i < values.length; i++)
{
var val1 = values[i];
if(val1.type != "A")
continue;
val1.childrenIDs = [];
for(var j = 0; j < values.length; j++)
{
var val2 = values[j];
switch(val2.type)
{
case "B":
if(contains(val2.parentIDs, val1.id))
val1.childrenIDs.push(val2);
break;
default:
break;
}
}
result.push(val1);
}
return result;
function contains(a, obj) {
var i = a.length;
while (i--) {
if (a[i] === obj) {
return true;
}
}
return false;
}
}
May be no "blue-print" solution but it works and I'll optimize it later. :-)
You can't use nested functions, in you case I'll recommend to use reduce function after map function.
So you need paste you GetAllSites function code to reduce
And don't forget to realize rereduse logic
Related
I have an array of objects which I am trying to loop over and check for a common key if it exists for all objects. if the specific key does not exist for all objects I return false.
Here is my code
var x = [{
"item": "alpha",
"value": "red"
}, {
"item": "beta",
"value": "blue"
}, {
"item": "beta",
"value": "gama"
}]
function test(obj) {
var count = 0;
var out = false;
for (var i = 0; i < obj.length; i++) {
if (obj[i].hasOwnProperty('value')) {
count = i;
}
}
if (count == obj.length) {
out = true
}
}
console.log(test(x))
I am getting undefined. Cant figure out what am I missing here
A really simple way to do this is to use Array#every like this
var x = [{
"item": "alpha",
"value": "red"
}, {
"item": "beta",
"value": "blue"
}, {
"item": "beta",
"value": "gama"
}]
function test(obj) {
return obj.every(a => a.hasOwnProperty("value"));
}
console.log(test(x))
Update
As rightfully mentioned by this comment first.
Here can be the simple solution for this object:
var x = [{
"item": "alpha",
"value": "red"
}, {
"item": "beta",
"value": "blue"
}, {
"item": "beta",
"value": "gama"
}];
function test(obj) {
var keyCount = 0;
obj.forEach(function (item, index) {
item.hasOwnProperty('value') && ++keyCount;
});
return keyCount == obj.length;
}
console.log(test(x));
Here is my implementation, which finds every matching key, even nested keys, given a set of objects:
function recurse_obj(obj, cb, _stack = []) {
for (var k in obj) {
cb(k, obj[k], _stack);
if (obj.hasOwnProperty(k) && (obj[k] instanceof Object)) {
_stack.push(k);
recurse_obj(obj[k], cb, _stack);
_stack.pop();
}
}
}
function obj_all_keys(obj) {
var tmp = [];
recurse_obj(obj, (k, v, stack) => {
var ext = (stack.length) ? "." : "";
tmp.push(stack.join(".").concat(ext, k));
});
return tmp;
}
function key_intersection(...objs) {
var lookup = {};
objs.forEach(o => {
obj_all_keys(o).forEach(k => {
if (k in lookup === false)
lookup[k] = 0;
lookup[k]++;
});
});
for (var k in lookup)
if (lookup[k] !== objs.length)
delete lookup[k];
return lookup;
}
Here is the calling code:
var me = { name: { first: "rafael", last: "cepeda" }, age: 23, meta: { nested: { foo: { bar: "hi" } } } };
console.log(key_intersection(me, { name: { first: "hi" } }));
Output: { name: 2, 'name.first': 2 }
The object returned includes only the keys that are found in all the objects, the set intersection, the counts are from book-keeping, and not removed in the callee for performance reasons, callers can do that if need be.
Keys that are included in other nested keys could be excluded from the list, because their inclusion is implied, but I left them there for thoroughness.
Passing a collection (array of objects) is trivial:
key_intersection.apply(this, collection);
or the es6 syntax:
key_intersection(...collection);
I'm using jsTree and have tree an structured JSON object.
[{
"id": 1,
"text": "TEXT_ONE",
"children": [
{
"id": 2,
"text": "TEXT_TWO",
"children": [
{
"id": 3,
"text": "TEXT_THREE",
"children": [
]
},
{
"id": 4,
"text": "TEXT_FOUR",
"children": [
]
}
]
},
{
"id": 5,
"text": "TEXT_FIVE",
"children": [
]
}
]
},
{
"id": 6,
"text": "TEXT_SIX",
"children": [ ]
}]
I want to get the the object based on the "id" of the object.
For example if i have a function getIdFromTree(3) it will return me the JSON object as following:
{
"id": 3,
"text": "TEXT_THREE",
"children": []
},
How I do that in Javascript/JQuery?
Try this
function getObjById (tree, id) {
if(tree.id === id) {
return tree;
}
if(tree.children) {
for(var i = 0, l = tree.children.length; i < l; i++) {
var returned = getObjById(tree.children[i], id);
if(returned) {
// so that the loop doesn't keep running even after you find the obj
return returned;
}
}
}
}
Call this as follows
getObjById({children: tree}, 3); // tree is the array object above.
function findById (tree, id) {
var result, i;
if (tree.id && tree.id === id) {
result = tree;
// Revalidate array list
} else if (tree.length) {
for (i = 0; i < tree.length; i++) {
result = findById(tree[i], id);
if (result) {
break;
}
}
// Check childrens
} else if (tree.children) {
result = findById(tree.children, id);
}
return result;
}
Use filter Methode off Array
data.filter(function (obj){ obj.id== 3});
try this.... Es6
function *getObjectById(data, id) {
if (!data) return;
for (let i = 0; i< data.length; i++){
let val = data[i];
if (val.id === id) yield val;
if (val.children) yield *getObjectById(val.children , id);
}
}
now
getObjectById(arrayOfObjects, id).next().value;
try this with most effective and efficient way..
function getObjById (tree, id) {
for(var i= 0;i<tree.length;i++)
{
if(tree[i].id===id)
{
return tree[i];
}
if(tree[i].children)
{
var returned = getObjById(tree[i].children,id);
if(returned!= undefined)
return returned;
}
}
};
link:
https://jsfiddle.net/aa7zyyof/14/
I have this json file:
var data = [{
"id": 0,
"parentId": null,
"name": "Comapny",
"children": [
{
"id": 1235,
"parentId": 0,
"name": "Experiences",
"children": [
{
"id": 3333,
"parentId": 154,
"name": "Lifestyle",
"children": []
},
{
"id": 319291392,
"parentId": 318767104,
"name": "Other Experiences",
"children": []
}
]
}
]
}];
I need to find object by id. For example if need to find an object with id:319291392, I have to get:
{"id": 319291392,"parentId": 318767104,"name": "Other Experiences","children": []}
How can I do that?
I tried to use this function:
function findId(obj, id) {
if (obj.id == id) {
return obj;
}
if (obj.children) {
for (var i = 0; i < obj.children.length; i++) {
var found = findId(obj.children[i], id);
if (found) {
return found;
}
}
}
return false;
}
But it doesn't work as it's an array of objects.
If your starting point is an array, you want to invert your logic a bit, starting with the array rather than with the object:
function findId(array, id) {
var i, found, obj;
for (i = 0; i < array.length; ++i) {
obj = array[i];
if (obj.id == id) {
return obj;
}
if (obj.children) {
found = findId(obj.children, id);
if (found) {
return found;
}
}
}
return false; // <= You might consider null or undefined here
}
Then
var result = findId(data, 319291392);
...finds the object with id 319291392.
Live Example
This should work for you:-
var serachById = function (id,data) {
for (var i = 0; i < data.length; i++) {
if(id==data[i].id)
return data[i];
if(data[i].children.length>0)
return serachById(id,data[i].children);
};
return null;
}
console.log(serachById(0,data));
Here is another simple solution using object notation.
This solution will work even if you decide to get rid of teh array and use object notation later on. so the code will remain the same.
It will also support the case when you have element with no children.
function findId(obj, id) {
var current, index, reply;
// Use the object notation instead of index.
for (index in obj) {
current = obj[index];
if (current.id === id) {
return current;
}
reply = findId(current.children, id);
if (reply) {
return reply;
}
// If you reached this point nothing was found.
console.log('No match found');
}
}
console.log(findId(data, 319291392));
do it so:
for (var obj in arr) {
if(arr[obj].id== id) {
console.log(arr[obj]);
}
}
I have a JSON data structure as shown below:
{
"name": "World",
"children": [
{ "name": "US",
"children": [
{ "name": "CA" },
{ "name": "NJ" }
]
},
{ "name": "INDIA",
"children": [
{ "name": "OR" },
{ "name": "TN" },
{ "name": "AP" }
]
}
]
};
I need to change the key names from "name" & "children" to say "key" & "value". Any suggestion on how to do that for each key name in this nested structure?
I don't know why you have a semicolon at the end of your JSON markup (assuming that's what you've represented in the question), but if that's removed, then you can use a reviver function to make modifications while parsing the data.
var parsed = JSON.parse(myJSONData, function(k, v) {
if (k === "name")
this.key = v;
else if (k === "children")
this.value = v;
else
return v;
});
DEMO: http://jsfiddle.net/BeSad/
Try this:
function convert(data){
return {
key: data.name,
value: data.children.map(convert);
};
}
Or if you need to support older browsers without map:
function convert(data){
var children = [];
for (var i = 0, len = data.children.length; i < len; i++){
children.push(convert(data.children[i]));
}
return {
key: data.name,
value: children
};
}
You could use a function like this :
function clonerename(source) {
if (Object.prototype.toString.call(source) === '[object Array]') {
var clone = [];
for (var i=0; i<source.length; i++) {
clone[i] = goclone(source[i]);
}
return clone;
} else if (typeof(source)=="object") {
var clone = {};
for (var prop in source) {
if (source.hasOwnProperty(prop)) {
var newPropName = prop;
if (prop=='name') newPropName='key';
else if (prop=='children') newPropName='value';
clone[newPropName] = clonerename(source[prop]);
}
}
return clone;
} else {
return source;
}
}
var B = clonerename(A);
Note that what you have isn't a JSON data structure (this doesn't exist as JSON is a data-exchange format) but probably an object you got from a JSON string.
I have a JSON tree structure:
nodes =
[
{
"name": "user1",
"children": [
{
"name": "user2"
},
{
"name": "user3",
"children": [
{
"name": "user4"
}
]
},
{
"name": "user5"
}
]
}
]
that I would like to convert to a parent-link structure:
[{"name": "user1","parent": "null"},
{"name": "user2","parent": "user1"},
{"name": "user3","parent": "user1"},
{"name": "user4","parent": "user3"},
{"name": "user5","parent": "user1"}]
I have tried to traverse the tree recursively but without success accessing the parent object:
rebuild(nodes,parentLink);
function parentlink(key,value) {
var obj = { name: value , parent: ??? };
if (key == "name"){
nodes.push(obj);
}
}
function rebuild(o,func) {
for (i in o) {
func.apply(this,[i,o[i]])
if (typeof(o[i])=="object") {
traverse(o[i],func,nodes);
}
}
}
In developer tools I can see the parent objects for each child, but I don't know how to access them. What should I do to add the parent to each user?
I'm not gonna lie, I didn't bother looking at your code - this is how I would do it:
http://jsfiddle.net/J6G2W/1/
function processChildren(item, ret, parent) {
for (var i = 0; i < item.length; i++) {
var cur = item[i];
var cur_name = cur.name;
ret.push({"user": cur_name, "parent": parent});
if ("children" in cur && cur.children.length > 0) {
processChildren(cur.children, ret, cur_name);
}
}
}
var all = [];
processChildren(nodes, all, null);
console.log(JSON.stringify(all));
Output is:
[{"user":"user1","parent":null},{"user":"user2","parent":"user1"},{"user":"user3","parent":"user1"},{"user":"user4","parent":"user3"},{"user":"user5","parent":"user1"}]
Which seems to be what you're looking for. You're welcome to modify what of my code to work more like yours, I just thought I'd share what I'd do :)
UPDATE:
If, for some reason, you want to make it more extendable, you can customize which keys are the "name" and which are the "children"...for example:
http://jsfiddle.net/J6G2W/2/
function startProcess(item, ret, key_look, children_look, parent) {
function processChildren(item2, ret2, parent2) {
for (var i = 0; i < item2.length; i++) {
var cur = item2[i];
var cur_name = key_look in cur ? cur[key_look] : null;
ret.push({"user": cur_name, "parent": parent2});
if (children_look in cur && cur[children_look].length > 0) {
processChildren(cur[children_look], ret, cur_name);
}
}
}
processChildren(item, ret, parent);
}
var all = [];
startProcess(nodes, all, "name", "children", null);
console.log(JSON.stringify(all));
Notice how you only have to specify the key_look, children_look arguments once. The inner function can access those parameters while only passing the important things each recursion. This probably isn't important, I just wanted to figure it out :)