MongoDB arrays vs objects - javascript

Lets say I want to maintain a list of items per user (in MongoDB with Mongoose ODM in Node.js environment) and later query to see if an item is owned by a user. For example, I want to store all of the favorite colors of each user, and later see if a specific color is owned by a specific user. It seems to me that it would be better to store the colors as an embedded object within the user document, rather than an array within the user document. The reason why is that it seems more efficient to check to see if a color exists in an object as I can just check to see if the object property exists:
if(user.colors.yellow){
//true case
} else {
//false case
}
Versus an array where I have to iterate through the entire array to see if the color exists somewhere in the array:
for (var i = 0; i < user.colors.length; i++) {
if(user.colors[i] === "yellow"){
//true case
} else {
//false case
}
}
However, from many of the examples I've seen online, it seems like using arrays for this type of thing is fairly prevalent. Am I missing something? What are the pros/cons, and best way to do this?

You don't have to use a for-loop if the colors are stored as an array. You can just use indexOf, as in:
if(user.colors.indexOf("yellow") != -1){
//true case
}
That said, it really shouldn't matter either way whether you use an embedded document or array; it's not like one or the other is going to give a huge performance advantage.

You frequently see embedded arrays used to store this type of information in MongoDB collections because if you add an index to the array property they're efficient to query and they use a natural syntax. In this case something like the following (assuming a users collection that contains a colors array property):
db.users.find({id: 1, colors: 'yellow'})
If you did this with individual color properties you'd have a more awkward looking query like this and you'd have to separately index each color (instead of just colors like you would above):
db.users.find({id: 1, 'colors.yellow': true})

Related

How do I iterate through objects stored in a firebase array in JavaScript?

At the moment I am storing a few objects in Firebase. After successfully retrieving the items from Firebase and storing them in a firebaseArray, I want to further thin out the unwanted elements by deleting the elements in the firebaseArray that do not have the desired property. Consider my code at the moment, that does not do as wanted, however there are no errors in the console:
var querylatestPosts = firebase.database().ref("Topics");
$scope.latestPosts = $firebaseArray(querylatestPosts);
console.log($scope.latestPosts) ;
$scope.latestPosts.forEach(function(el) {
if ($scope.checkWorldview(el) == false) {
delete $scope.latestPosts.el ;
}
});
(Note I am unable to log 'el' in the console, nor does the forEach seem to execute, as I can log nothing in the function in the console)
The 'checkWorldview' function behaves as expected when elements are fed in different instances and returns false if the required property is not present in the element under consideration. Thus if the function returns false, I want to delete the specific element in $scope.latestPosts that does not contain the wanted property.
I hope this is clear, thank you in advance for any help you can offer!
The way you are using the $firebaseArray isn't recommended by the docs (see here), which state that $firebaseArray is read only and should not be manipulated.
So you have a few options:
Instead of filtering the array on the client-side, you should modify the query you're using to retrieve data from Firebase to only get elements that have the desired property (ex: use 'equalTo' in the query)
OR
Don't use a $firebaseArray because you're not using it in the way it was intended. Use a regular, good ol' fashion JavaScript array instead.
** Also, just a general comment: don't delete elements from an array as you loop through it as this is generally bad practice (we don't expect arrays to have elements added/removed while we loop through them). Instead, use Array.filter.

Should argument types be verified in JavaScript?

This should be simple question.
I have been using JavaScript for a couple years, and strongly typed languages (such as Java and C++) for even longer. I recall learning that, in the strongly typed languages, having to check types of arguments before doing stuff with them is symptom of bad code. However, does this carry over to languages like JavaScript?
/* in client-side JavaScript, for example, I find myself automatically doing stuff like this:
function myFunction(array1, array2)
{
if (array1 !== Array.from(array1)) return null;
if (array2 !== Array.from(array2)) return null;
// some array action here with arrays array1,array2
}
*/
Yes, before using it, you could take Array.isArray for checking if a variable is an array.
The Array.isArray() function determines whether the passed value is an Array.
The check for type is necessary if data comes from an unknown source, like to work with a alibrary, where the vendor does not know in advance what type of data the user supplies.
Some libraries uses a mixed mode for data where the data could be a single item or an array of items. In this case a check is necessary to determine if the item has to be wrapped in an array or not.
function myFunction(array1, array2) {
if (!Array.isArray(array1)) return null;
if (!Array.isArray(array2)) return null;
// some array action here with arrays array1,array2
}
The only place I have checked it was while writing the test cases.
I would say test case is the perfect example. We will be checking for both positive and negative scenarios. I hope you understand, if not let me know.

How to traverse JS object and all arrays and objects inside to compare it with its copy?

I have a selectedItem object in Angular, it contains other objects and arrays. I create a deep copy using a JSON trick:
$scope.editableItem = JSON.parse(JSON.stringify($scope.selectedItem))
Then I use editableItem model in inputs, change some values inside. selectedItem doesn't change. Then I want to send via PATCH all the changes made, but not the fields which were not changed. So I need to strip the editableItem from all fields that are the same in unchanged selectedItem.
How to do this efficiently? I was thinking about traversing object recursively using Underscore, but I'd really like to know if it's a good way of thinking before I tackle it.
Alternatively I could probably create third object which would only contain touched fields from the second one, added dynamically, but I'm not sure how to approach this.
EDITED:
To be clear, I expect the answer to be generic and assume the most complicated object structure possible. For example no answers from this question are applicable here as they either assume the object has only simple fields or they need to have Angular watcher explicitly set for every field separately.
I do something similar with a function like this:
function getUpdateObject(orig, current) {
varChanges = {};
for (var prop in orig) {
if (prop.indexOf("$") != 0 && orig[prop] !== current[prop]) {
varChanges[prop] = current[prop];
}
}
return varChanges ;
};
I don't think this will get you all the way there. I'm not using it in any scenarios where the objects have member objects or arrays, but you should be able to test if "prop" is an object or array and call it recursively. The biggest caveat I see to that approach is if you have a deep, nested structure, you may not detect a change until you're down several levels. You'd probably have to keep the full potential hierarchy for a changed property in memory, then when you detect a change at a lower, level, write the whole hierarchy to the output object.
This is what I ended up with. Maybe it'll help someone. I used DeepDiff library. Code is in CoffeScript, should be easy to translate to JavaScript if anyone needs it.
$scope.getChangesObject = () ->
selected = $scope.selectedItem
editable = $scope.editableItem
changes = {}
differences = DeepDiff(selected, editable)
for diff in differences
formattedPath = ""
for pathPart, index in diff.path
if index isnt diff.path.length - 1
formattedPath += pathPart + "."
else
formattedPath += pathPart
changes[formattedPath] = editable[formattedPath]
changes

finding all keys that map to a value in javascript. And efficient alternatives

I'm working on an application in javascript where each user is in a room. No two users share the same name and no two rooms share the same name. Currently I have it set up like this:
var userroommap = {
username: "room",
username2: "room",
username3: "room2"
}
getting the room a user is in is as simple as
userroommap["user"]
but in order to get all users which are present in a room I would have to iterate over the entire userroommap like so:
for (var x in userroommap) {
if (userroommap[x] == "room")
//user x is present in room
}
}
In my application I must know which users are in which rooms very often so I am considering using another object to hold all users in a room, something like:
var roomusermap = {
room:["username", "username2"],
room2:["username3"]
}
Adding users to the room is trivial because all you have to do is append to an array, however removing a username from a room requires iterating over the array and becomes a decent operation. This already is a decent solution to my problem, but I became curious if there was a better solution. So: is there a better way to (i) store the roomusermap, perhaps without arrays? or, alternatively (ii) find all users in a room?
The data-structure described in the previous answer is called a BiMap.
A BiMap ideally provides equivalent performance for value: keys lookup operations as for key: values lookups. It is typically implemented by internally managing two separate maps (one with a forward-mapping {key:values} and one with a reverse-mapping {value:keys}).
Here's an existing implementation to use if you're not rolling your own. https://www.npmjs.com/package/bimap
Unless you've identified a genuine, real-world performance problem, I'd stick with the simple solution.
That said, a few thoughts for you:
All modern JavaScript engines give you the Object.keys function, which returns an array of an object's own enumerable properties. This may be more efficient than your for-in loop for two reasons:
It's happening within the engine's code, which lets the engine optimize
for-in looks for enumerable properties in prototype objects, whereas Object.keys knows it's only supposed to look in that specific object
Your roomusermap can contain maps per room, it doesn't need to use arrays.
var roomusermap = {
room: {
username: user,
username2: user2
},
room2: {
username3: user3
}
};
Adding a user to a room becomes:
userroommap[username] = roomname;
roomusermap[roomname][username] = user;
Removing a user is:
delete userroommap[username];
delete roomusermap[roomname][username];
If you're seeing performance problems with those map objects, something to keep in mind is that removing a property from an object (delete) puts the object into "dictionary mode" on several JavaScript engines (having previously been in a more optimized state), significantly impacting the time required to look up properties on that object.
So in the very hypothetical case where the property lookup performance starts to be an issue, you could consider storing undefined rather than deleting the property. E.g., instead of:
delete userroommap[username];
delete roomusermap[roomname][username];
you'd do
userroommap[username] = undefined;
roomusermap[roomname][username] = undefined;
However, you'd have to adjust your checks for whether a user is in a room, and you couldn't use Object.keys (on its own) to get the list anymore since you have to weed out the properties with the value undefined. You could use Object.keys with filter:
var map = roomusermap[roomname];
var users = Object.keys(map).filter(function(username) {
return map[username] !== undefined;
});
So you'd really want to do that only if you've identifed a genuine problem caused by objects going into dictionary mode.

how does javascript move to a specific index in an array?

This is more a general question about the inner workings of the language. I was wondering how javascript gets the value of an index. For example when you write array[index] does it loop through the array till it finds it? or by some other means? the reason I ask is because I have written some code where I am looping through arrays to match values and find points on a grid, I am wondering if performance would be increased by creating and array like array[gridX][gridY] or if it will make a difference. what I am doing now is going through a flat array of objects with gridpoints as properties like this:
var array = [{x:1,y:3}];
then looping through and using those coordinates within the object properties to identify and use the values contained in the object.
my thought is that by implementing a multidimensional grid it would access them more directly as can specify a gridpoint by saying array[1][3] instead of looping through and doing:
for ( var a = 0; a < array.length; a += 1 ){
if( array[a].x === 1 && array[a].y === 3 ){
return array[a];
}
}
or something of the like.
any insight would be appreciated, thanks!
For example when you write array[index] does it loop through the array till it finds it? or by some other means?
This is implementation defined. Javascript can have both numeric and string keys and the very first Javascript implementations did do this slow looping to access things.
However, nowadays most browsers are more efficient and store arrays in two parts, a packed array for numeric indexes and a hash table for the rest. This means that accessing a numeric index (for dense arrays without holes) is O(1) and accessing string keys and sparse arrays is done via hash tables.
I am wondering if performance would be increased by creating and array like array[gridX][gridY] or if it will make a difference. what I am doing now is going through a flat array of objects with gridpoints as properties like this array[{x:1,y:3}]
Go with the 2 dimension array. Its a much simpler solution and is most likely going to be efficient enough for you.
Another reason to do this is that when you use an object as an array index what actually happens is that the object is converted to a string and then that string is used as a hash table key. So array[{x:1,y:3}] is actually array["[object Object]"]. If you really wanted, you could override the toString method so not all grid points serialize to the same value, but I don't think its worth the trouble.
Whether it's an array or an object, the underlying structure in any modern javascript engine is a hashtable. Need to prove it? Allocate an array of 1000000000 elements and notice the speed and lack of memory growth. Javascript arrays are a special case of Object that provides a length method and restricts the keys to integers, but it's sparse.
So, you are really chaining hashtables together. When you nest tables, as in a[x][y], you creating multiple hashtables, and it will require multiple visits to resolve an object.
But which is faster? Here is a jsperf testing the speed of allocation and access, respectively:
http://jsperf.com/hash-tables-2d-versus-1d
http://jsperf.com/hash-tables-2d-versus-1d/2
On my machines, the nested approach is faster.
Intuition is no match for the profiler.
Update: It was pointed out that in some limited instances, arrays really are arrays underneath. But since arrays are specialized objects, you'll find that in these same instances, objects are implemented as arrays as well (i.e., {0:'hello', 1:'world'} is internally implemented as an array. But this shouldn't frighten you from using arrays with trillions of elements, because that special case will be discarded once it no longer makes sense.
To answer your initial question, in JavaScript, arrays are nothing more than a specialized type of object. If you set up an new Array like this:
var someArray = new Array(1, 2, 3);
You end up with an Array object with a structure that looks more-or-less, like this (Note: this is strictly in regards to the data that it is storing . . . there is a LOT more to an Array object):
someArray = {
0: 1,
1: 2,
2: 3
}
What the Array object does add to the equation, though, is built in operations that allow you to interact with it in the [1, 2, 3] concept that you are used to. push() for example, will use the array's length property to figure out where the next value should be added, creates the value in that position, and increments the length property.
However (getting back to the original question), there is nothing in the array structure that is any different when it comes to accessing the values that it stores than any other property. There is no inherent looping or anything like that . . . accessing someArray[0] is essentially the same as accessing someArray.length.
In fact, the only reason that you have to access standard array values using the someArray[N] format is that, the stored array values are number-indexed, and you cannot directly access object properties that begin with a number using the "dot" technique (i.e., someArray.0 is invalid, someArray[0] is not).
Now, admittedly, that is a pretty simplistic view of the Array object in JavaScript, but, for the purposes of your question, it should be enough. If you want to know more about the inner workings, there is TONS of information to be found here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
single dimension hash table with direct access:
var array = {
x1y3: 999,
x10y100: 0
};
function getValue(x, y) {
return array['x' + x + 'y' + y];
}

Categories

Resources