MongoDB get specific key from document based on given value - javascript

I am getting a Document as:
async findOne(id: string) {
return await this.gameModel.findById(id);
}
async update(id: string, updateGameDto: UpdateGameDto) {
const game = await this.findOne(id)
// This gives all keys as expected
for( const key in game){
console.log(key)
}
// ...
const keys = Object.keys(game) // [ '$__', '$isNew', '_doc' ]
return;
}
Why does Object.keys(game) only return those 3 keys? If it only returns those keys, obviously I can't get the key as so:
const specificKeyByValue = Object.keys(game).find(key => game[key] === "SomeValue")
I could create a function that simply returns the key with a for loop like;
const getKeyByValue = (obj, value) =>
{
for( const key in obj)
{
if(obj[key] === value) return key;
}
}
But I prefer to stay away from creating extra functions if I don't have to. Any idea why this Object.Keys() variant doesn't work?

There are few differences in behaviour of Object.keys and for-in.
for-in iterates over all enumerable properties of an object that are keyed by strings (ignoring ones keyed by Symbols), including inherited enumerable properties.
As per the MDN docs this is what for-in does:
The loop will iterate over all enumerable properties of the object
itself and those the object inherits from its prototype chain
(properties of nearer prototypes take precedence over those of
prototypes further away from the object in its prototype chain).
A for...in loop only iterates over enumerable, non-symbol properties.
Objects created from built–in constructors like Array and Object have
inherited non–enumerable properties from Array.prototype and
Object.prototype, such as Array's indexOf() method or Object's
toString() method, which will not be visited in the for...in loop.
And the difference (docs)
Object.keys() returns an array whose elements are strings
corresponding to the enumerable string-keyed property names found
directly upon object. This is the same as iterating with a for...in
loop, except that a for...in loop enumerates properties in the
prototype chain as well. The order of the array returned by
Object.keys() is the same as that provided by a for...in loop.
Check few examples here

Related

Can't list window.document properties - why?

Running this JavaScript lists in Firefox 60.2 only one property ("location"), but there are many others, like "document.title" etc.
window.console.log("List props: " + Object.keys(window.document).sort().join(' / '));
Why is it this way? Safety? How is this done technically?
How can I list all properties?
Object.keys(o) returns the own, enumerable properties of o.
Own: properties defined directly on o, not on its prototype chain:
Enumerable: a flag that controls if a given property is included when listing an object's properties.
In this case most of the keys you expect are defined on another object in in document's prototype chain:
document.hasOwnProperty("title"); // false
document.__proto__.__proto__.hasOwnProperty("title"); // true
document.__proto__.__proto__.propertyIsEnumerable("title"); // true
You can use a for... in loop to find the enumerable properties that are defined on an object or its prototype chain:
for (let key in window.document) {
console.log(key);
}
The reason is that Object.keys() returns returns an array of strings that represent all the enumerable properties of the given object.
Try this to see which properties of document are enumerable
for(let key in document){
let isEnumerable = document.propertyIsEnumerable(key);
console.log(`docment['${key}'] isEnumerable?:${isEnumerable}`);
}
However as the previous answer has stated you can use a for-in loop to get all properties in an array sort them and join them
I couldn't find an official reason for it not working with window.document but it seems you can reproduce this behavior with other variables as well.
The issue seems to be Object.keys() not returning everything from these variables.
If you're still trying to get all properties of document, you can still use
var props = [];
for(var prop in window.document) {
props.push(prop);
}
console.log("List props: " + props.sort().join('/'));
Which will do the exact same thing as your approach.

Accessing Javascript Object Keys

I'm having the hardest figuring out how to this (seems so simple).
I have a Javascript Object as shown here
Output of console.log(data):
{"prevExists":false,"pubKey":"b5","ID":"5f1"}
I'm trying to access the different key value pairs.
When I try the expected methods, I get back undefined.
I have tried:
var pubKey = "pubKey";
data.pubKey
data[pubkey];
data["pubKey"];
I know I'm missing something really obvious here.
You have several ways of accessing keys, depending on which keys you're talking about.
In your example, any of those would work:
var data = {
"prevExists":false,
"pubKey":"b5",
"ID":"5f1"
};
// Access all keys of enumerable string-keyed properties
Object.keys(data).forEach((key) => console.log(key,data[key]));
// Access all keys of enumerable and non-enumerable string-keyed properties
Object.getOwnPropertyNames(data).forEach((key) => console.log(key,data[key]));
// Access all keys of enumerable string-keyed properties of your object, its prototype, and all the prototype chain...
for (let key in data)
console.log(key,data[key]);
If you want to have a better understanding of what is an object's property, you can have a look at this recent answer I wrote on the topic.
You can use Object.keys and a foreach loop to access the properties on the object.
var data = {"prevExists":false,"key":"b5","ID":"5f1"};
Object.keys(data).forEach(function(key) {
console.log('key - ' + key + ' :: value - ' + data[key]);
});
First you need to create a reference to your object. Like this:
var myObj = { "prevExists": false, "key": "b5", "ID": "5f1" };
Then, you can access the elements using their keys:
console.log(myObj["prevExists"]);
Console exit:
false
Good luck!
Use the Object.keys method
var data = {"prevExists":false,"pubKey":"b5","ID":"5f1"}
console.log(Object.keys(data));
Object.keys()
The Object.keys() method returns an array of a given object's own enumerable properties, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
You are confusing yourself with the line var pubKey="pubKey".
There are 2 ways to access object parameters:
const data = {"prevExists":false,"pubKey":"b5","ID":"5f1"};
// var pubKey = "pubKey"; This line is not needed
1) data.pubKey
If you use the dot operator (.), then you reference it with the key name.
2) data["pubKey"];
If you use brackets ([]), then you use the string that matches the key.
If you add the line:
const pubKey = "pubKey";
, then data[pubKey] will also work, because it evaluates to data["pubKey"]

Why can't I get properties count of navigator object in JavaScript?

Run in your browser (ES5+)
var propCount = Object.keys(navigator).length;
console.log(propCount); // 0
If you do it for a plain object like that
let obj = {
foo: 'bar',
breaking: 'bad'
}
let propCount = Object.keys(obj).length;
console.log(propCount); // 2
Why does it happen?
Sorry if it might relate to another problem like when Object.keys(obj) is only counting it for simple objects which do not contain functions/arrays, but this the 1st time I encountered with it.
And would like to know the reason of it.
Object.keys() function returns properties of the object that are directly assigned to it. If you do the following:
console.log(navigator.hasOwnProperty('permissions')); // false
If you want to see properties of navigator do the following:
for(let i in navigator){
console.log(i);
}
It will list all the properties of navigator object because for ... in ... loop includes object's prototype.
That's because most properties of navigator are set on the Navigator prototype, which the navigator instance inherits, and Object.keys only returns the properties set on the navigator object itself.
You can get those properties from the prototype with this:
Object.keys(Object.getPrototypeOf(navigator));
On a side note, Firefox has the following properties in the navigator object itself:
[ "doNotTrack", "mozPay", "mozContacts", "mozApps" ]
There are enumerable and non enumerable properties in javascript. Object.keys() would return the enumerable own properties of an object. So in navigator object, it seems that there is no enumerable own properties. Hence Object.keys(navigator) is returning an empty array.
From the doc,
The Object.keys() method returns an array of a given object's own
enumerable properties, in the same order as that provided by a
for...in loop.
If you want to list out all the enumerable and non enumerable properties of a certain object, then you have to write your own logic by using Object.getOwnPropertyNames().
Note : getOwnPropertyNames will return both enum/non enum own
properties of an object.
function getAllProps(obj, props = []){
if(Object.getPrototypeOf(obj) == null){ return props; }
return getAllProps(Object.getPrototypeOf(obj),
props.concat(Object.getOwnPropertyNames(obj)));
}
console.log(getAllProps(navigator));
//This will give you all the properties.
If you use for..in loop then that will give you only the enumerable properties across the prototype chain. And you will have to miss the non enumerable properties.

Why are Object.keys() and for ... in different?

I'm trying to do a bit of browser object discovery, figuring out browser built-ins etc...
I noticed different results when trying to get at the window object's properties (just FYI I'm using Chrome Version 41.0.2272.89 (64-bit)).
Object.keys(window).length;
returns 7 keys. From the docs Object.keys() returns the enumerable properties of an object.
But the docs also say that for ... in iterates over the enumerable properties of an object. However:
var i = 0;
for (var propertyName in window) {
i++;
}
returns a count of 177.
Why is this different? Shouldn't they both only be returning the count of enumerable properties?
for-in loops over the object's own enumerable properties and the enumerable properties of its prototype (and its prototype, etc.). Object.keys only lists the object's own enumerable properties.
So Object.keys builds an array something like this:
var keys = [];
var key;
for (key in object) {
if (object.hasOwnProperty(key)) { // But using an internal, non-overrideable
// operation, not literally the method
keys.push(key);
}
}
Note the hasOwnProperty check (it's not really a call to the method, it's an internal check that can't be tricked by replacing the method or similar).

JS "for (var key in arr)" > throws my own Array.prototypes, but not the inherent ones. Why?

I accidently used an iteration like
for (var key in arr)
{
alert(key);
}
and got an output that rose some questions. (I wanted to iterate through a JSON, so I used 'key' - an 'i' for index would be more suitable in this case, no question :-)
The first outputs were the indeces (like '0', '1' etc.) - still no question - but at last it throws the names of my Array.prototypes, I declared somewhere else in the code. Prototypes like
Array.prototype.lastIndex = function(){
return this.length - 1;
}
and it throws just 'lastIndex'.
What I don't understand: Are my own, non-inherent prototypes distinct from the JS-inherent ones like splice(), slice() ... ?
And: Why does it throw them at all? They are part of the Array.prototype, but not of a particular Array object!?
Thx in advance!
When you attach a property to an object, by default, the property will be enumerable.
If a property is enumerable, for..in will pick it up.
So, when you are iterating an array object with for..in, it first gives all the enumerable properties in the current object. Then, it goes up the prototype chain and gives all the enumerable properties of the corresponding objects. So, in your case, it goes up the chain and finds an enumerable property called lastIndex in Array's prototype, includes that in the iteration.
If you define it with enumerable: false, like this
Object.defineProperty(Array.prototype, 'lastIndex', {
value: function() {
return this.length - 1;
},
enumerable: false
});
it wont show up in for..in iterations. Quoting MDN documentation for enumerable attribute,
The enumerable property attribute defines whether the property shows up in a for...in loop and Object.keys() or not.
Note: Always use normal for loops for array iterations.
Any array instances inherits from Array.prototype. So any change to the prototype will be reflected in those array instances as well.
If you wanted it to remain only to arr you would attach the function lastIndex just to it, so other array instances won't get affected.
So it appears in for..in loop, which iterates through enumerable properties, as lastIndex is an enumerable property.

Categories