parent = {
child0: {
data1:'foo',
data2: 'bar'
},
child1: {
data1:'foo',
data2: 'bar'
},
child2: {
data1:'foo',
data2: 'bar'
}
}
At first I was thinking I would set a parent:child key since I will need that data individually of its siblings. In some instances though, I will need to return all of the data within parent.
Should I just put the whole object in a parent key?
Are there downsides to this if a lot of gets and sets may only be for one of it's children?
Is there a way to call all parent data with a parent:child schema?
Thanks!
Try a hash - that gives you HGET to get just one child and HGETALL to get all of them.
Storing the whole object as JSON in a single key is also valid though, and keeps your code simple if your usage is a good fit. If the numbers aren't too large, it may make sense to always retrieve the whole object even when you only need to display one child object.
The main reason to avoid storing complex objects in a single key is write conflicts - if two connections can modify different children of one object at the same time a hash will be much less trouble.
You might consider taking advantage of the hash data type. Using the parent as a key to the hash and using (HGET key field) for a particular child or (HKEYS key) for all the children.
It would be interesting if someone would post benchmarks for hash commands HSET and HGET. The benchmarks for the list operations (LPUSH 88109.25 /sec) are (~23%) slower though (SET 114293.71 /sec). Presumably HSET is yet slower though listed O(1).
So I think you would speed optimize the decision by looking at the ratio of full family requests to individual child request in your code.
Related
I am interested in using vanilla Javascript objects and arrays to model data that has the data structure of a connected directed graph. One way to do this would be to use multiple object references within a single object tree to represent distinct edges of the graph. However, to use this efficiently, there needs to be a way to easily check what are the incoming edges to a given object (or put another way, for each object to know what all of it's parents are, and to know the property keys from each parent to itself.)
According to this older Stack Overflow post there is no built-in way to do this in Javascript: Get all object references in Javascript.
I've started making my own library called Parent Aware Objects that uses Proxy objects to intercept basic object assignment operations in order to keep track all the references to each object.
Before I go too far down this path, I wanted to ask if there might be an easier way to accomplish this.
This is the functionality I want:
const fido = {
name: 'Fido'
};
const alan = {
name: 'Alan',
pet: fido
}
const sarah = {
name: 'Sarah',
dogWalkerFor: fido
}
getParents(fido)
The function call getParents(fido) should return a list of entries that contains the alan object with key "pet" and sarah object with key "dogWalkerFor".
You would need a collection of all the nodes in the graph to search for:
const graphNodes = [fido, alan, sarah];
Then you can easily get all nodes that reference Fido:
graphNodes.filter(node => Object.values(node).includes(fido))
Of course, searching the entire graph every time is not really efficient. To do that, you would need to store the backedges on the node itself, or in a Map or something where you can easily look them up. This would then require updating that data structure every time you update your graph.
A little background on the problem
I've built a custom system to automatically watch some "store" properties that comes from a JSON of a nosql database. Nothing too complicated except the nesting (required for several reasons not discussed here) of objects.
The data structure looks like this:
{
store: {
objA: {
objB: {
prop1: 'some value'
}
}
}
}
However, since it's a nosql database that provide that store property, objB can just be NOT present after the load from the database.
Example of the template used
I have custom components that have props bound directly to that data store
<my-selector :value.sync="store.objA.objB.prop1">
</my-selector>
However, it crashes when "objB" is not present with the usual javascript error saying that it cannot get "objB" of undefined, but that is normal.
I'm trying to find a vuejs way to prepare the data for me.
Ideas
In order to counter that crash :
I can NOT use v-if in that case to mask the selector. Because that selector can be used even if the data is not yet set (example: for optional data).
I could fix the "load" function that gets the data from the database so it initialize the required properties (like objB) before assigning data to the data store. However, that would imply that my initial VueJS data object would contain these required properties as well. It's probably that I will use if I can't find any alternative solution, but I don't think that's the easiest way around because I would have to fix any incoming data before assignment.
My preferred choice would be to create a directive (or any other thing built in the template) that would add them for me if they are missing.
VueJS always evaluates the bindings value
I thought of that solution:
<my-selector v-autocreate="'store.objA.objB.prop1'" :value.sync="store.objA.objB.prop1">
</my-selector>
However the directive binding "v-autocreate" is not picked up first (checked with the debugger).
I did not find documentation relative of the order of load of directives or attributes.
I was also hoping to get all bindings of a node with the directive "bind"
function in order to NOT repeat the string, but it seems we can't get that information (I'm used to knockoutjs where we can pick all bindings assigned to a node in order to behave differently).
I would like to reach that goal but I'm not sure that it's possible (I would need something like a pre-bind / beforeBind event on directive haha) :
<my-selector v-autocreate :value.sync="store.objA.objB.prop1">
</my-selector>
Where v-autocreate would assure to do the vm.$set of the missing properties.
You could create a method that checks each property in an object path, creates it if it doesn't exist, then returns the value of the last property.
Example (not tested):
get(object, path) {
path = path.split('.')
let index = 0
const length = path.length
let val
while (object != null && index < length) {
let key = path[index++]
if(object[key] == null) {
this.$set(object, key, {})
}
object = object[key]
}
return val
}
Usage:
<my-selector :value="get(store,'objA.objB.prop1')">
</my-selector>
You may be interested in lodash's get function, which is what the code example is based on.
https://github.com/lodash/lodash/blob/master/get.js
I know understand more about how jQuery stores data.
Is there any advantage to doing one or the other of these:
$('#editCity').data('href', "xx");
var a = $('#editCity').data('href');
or
$('#editCity').attr('data-href', "xx");
var a = $('#editCity').attr('data-href');
One more related question.
If I have this:
var modal = { x: 'xx', y: 'yy' };
Can I also store this using .data( .. ) ?
Storing property values directly on DOM elements is risky because of possible memory leaks. If you're using jQuery anyway, the .data() mechanism is a wonderful and safe way to keep track of per-element information. It allows for storage of arbitrary JavaScript data structures too, not just strings.
edit — when your HTML markup contains data-foo attributes, those are implicitly read when the keys are accessed. That is, if your HTML looks like this:
<div id="div1" data-purpose="container">
Then in jQuery:
alert( $('#div1').data('purpose') ); // alerts "container"
Furthermore, jQuery will also do some "smart" analysis of the attribute values. If a value looks like a number, jQuery will return a number, not a string. If it looks like JSON, it de-serializes the JSON for you.
edit — here's a good trick: in the Chrome developer console (the "Console" view), you can type JavaScript expressions and have them evaluated. The evaluation is always done in the context of the page you're working on. If you select an element from the "Elements" view, then in the console the JavaScript symbol $0 will refer to that selected DOM element. Thus you can always inspect the "data" map for an element by going to the console and typing something like:
$($0).data("something");
The .data() function, if called with no parameters, returns all the key/value pairs:
$($0).data();
The most interesting point about the data function is that you can add any kind of object, for example your modal. And jQuery, as stated in the documentation, take care of avoiding memory leaks when the DOM changes :
The jQuery.data() method allows us to attach data of any type to DOM
elements in a way that is safe from circular references and therefore
free from memory leaks.
For strings, memory leaks aren't possible but the main difference is that the first solution is cleaner (more coherent if you might store other data than strings in other parts of your application), clearer (the intent is evident), and doesn't force CSS calculation (DOM isn't changed).
They both have advantages... That said, 99% of the time you should be using .data('whatever', value)
Advantages of using .data('whatever', value):
less apt to cause memory leaks because it's not using the DOM.
Slightly faster to pull data from memory than from the DOM.
Can put any type of object in it without serializing it to JSON first.
Advantages of using .attr('data-whatever', value):
compatible with .data('whatever')
allows you to select the element by the value: $('[data-whatever=foo]')
You can put any object in it, but it will need to serialize if it's a complex type.
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Javascript custom index accessor
If I were to write, say, a doubly-linked list object in Javascript, is there a way to reference this new list in a fashion like an array?
For instance, if I wanted the value of node 5, I'd like to query
newLinkedList[5]
instead of doing what I've been doing, which is something like
newLinkedList.getNode(5)
Basically, is there a way to "pretty up" references to custom data structures, or do you have to do it as a custom function each time?
Arrays in Javascript are really just objects with special handling for numerical properties. You can accomplish the same thing yourself, but currently Javascript doesn't provide a simple mechanism for transparent two-way accessing of those indices; you'll have to handle adding and deleting objects with named methods, but you can still benefit from reading them with array-like indexing.
Here's an example of a simple custom "Arrayish" object:
var ll_array = {};
ll_array.length = 0;
ll_array.addNode = function (newNode) {
this[this.length] = newNode;
this.length++;
};
ll_array.addNode('Foo');
ll_array.addNode('Bar');
console.log('Length: ' + ll_array.length);
console.log(ll_array);
console.log(ll_array[0]);
http://jsfiddle.net/rbmsJ/1/
The brute force method of traversing the list, then assigning each item in the traversal to an array element, is the first thing that comes to mind:
Pretend you have a LinkedList object. Let's also presume there are methods for iterating the list called Head, and Next. Now, caveat being that this is entirely untested, you could create a prototype toArray() method in a manner such as:
LinkedList.prototype.toArray() = function () { var array={};
var currentItem = list.head;
while (currentItem!=null){
array.addNode(currentItem);
currentItem=currentItem.Next;
}
return array;
}
Obviously this must allow for other presumed functions, but the idea is to traverse the linked list, and put a reference to each element in an array, and return it. Hope that helps in some way.
From your question:
objects are saved in a double-linked list.
you know the getNode(int n) method to get n-th element.
there are no way to allow you get the n-th element with array style, [n]. because linked lists are not arrays, the elements in a linked list are linked to each other, this data structure is different from ordinary array or JavaScript style array:named property.
Arrays ARE double linked lists without the links. To traverse right you simply increment the index, to traverse left you decrement the index.
You could write yourself a set of functions to perform the basic list operations and still have the facility of using simple indexing to reach any aribtrary element.
I was wondering what the advantage is of using data assignment to the DOM vs. NOT to the DOM
i.e. Assume we have said HTML
<a id="foo" href="#">foo!</a>
//Set attr data-me so it's <a id="foo" data-me="yay" href="#">foo!</a>
$('#foo').attr('data-me', 'yay');
//Retrieve the data 'yay'
$('#foo').data('data-me');
Over and above direct assignment:
var myInput = $('#foo');
//Add some data
$.data(myInput, 'data-me', 'yay');
//Retrieve the data 'yay'
$.data(myInput, 'data-me');
My understanding is that the later is MUCH faster and therefore I can't see the sense in adding data-someAttr all over the DOM when it's not required ?
They serve different purposes. Yes, it seems like they can be used to achieve the same thing, but under the hood there are differences.
While you can save simple values in attributes, you can not save DOM nodes, because you will create memory leaks. Neither can you save objects, arrays, functions, etc...
$.attr() might be faster than $('selector').data(), but it is not faster than the low-level method jQuery.data(). The first data method has much more overhead than the second, however the second one does not carry all the functionality of the first one. For example, it does not get the data out of the data- attributes.
Thus, I think it's best to use data- attributes at load time, so you can extract the data with $('selector').attr(), and handle the application state with $.data().
I'm not a guru, that' s for sure... but it appears to me that two obvious differences are the time/environment when the 'data' is set, and the structure(type) of data that will be stored/accessed.
Concider this scenario:
<a id="foo" data-me="some string data" href="#">foo!</a
This pice of html was maybe generated on the server side. If so,only the server side needs to know about the 'data-me' value origin. One limitation is that the attribute must be a string , or a string representation of an object (JSON)
var customData =
{
date:new Date(),
otherProp:'some value',
someFunc: function(a,b)
{
// function dody
}
};
$('#foo').attr('data-me', customData)
From the javascript(medium), at a certain moment, triggered by a certain event(time), you can use jQuery to bind a dom element to a given object (not necessarily a string)
So the latter way ($('#foo').attr('data-me', customData)), removes the 'only string' limitation and allows you to bind to a dom element any kind of js object , even functions.