how to inspect/iterate over an object in node? - javascript

I'm getting a result (the object) back from a mongoose query and want to replace/remove some keys, before I stringify the object and send it to the client.
When I console.log the object, everything is nice (all the keys are listed, nothing more). When I do a for..in on the object, hidden fields popup out of nowhere (and the keys of interest, don't). They make sense - they belong to mongoose - but I don't want them. Same thing happens, when using Object.keys or Object.getOwnPropertyNames on the Object - hidden fields popup, none useful.
So I wanted to inspect the element with util.inspect(obj,true,null,true) and log the result to console. The result on the console is the same, as if I'd console.logged the object directly without the inspection.
Now, two questions;
How do I correctly inspect an object, so that I actually get internal/hidden information about the object?
How can I iterate over the object and only get the fields? (yes, I am doing the hasOwnProperty check within the for..in loop)
//EDIT
OK, I got it. After some investigation, I realized, that the mongoose object proxies its properties and has a toJSON function, which explains why the console.logs were in the expected output structure. The solution is to use Mongoose own toObject method;
mongooseObj.toObject({ getters: true, virtuals: false })
This way, I can iterate over Object.getOwnPropertyNames and replace/remove keys I don't want the client to know about!

I'm going to guess that you're looking at the Document object returned by a mongoose query when you really just want to see the data. If my guess is correct, you'll probably want something like this:
Model.findOne({ name: 'john' }, function (err, doc) {
var data = doc.toObject();
// do whatever you need to with data
delete data.age;
delete data.weight;
data.isAwesome = true;
// now stringify the data and do something with it
callback(JSON.stringify(data));
});

Also if you want to access a certain field from a Document you can take a look at:
Document#get
// path
doc.get('age') // 47
// dynamic casting to a string
doc.get('age', String) // "47"

Related

Access Array with String key

I have two variables with JSON files. The first is a list of keys looks like this:
keylist = ["key1","key2","key3"]
The second one is generated from a database and looks like this:
data = {
"key1"{
#further data
},
"key2"{
#further data
},
"key3"{
#further data
}
}
Now I want to access the second element of the database with the key from the keylist
data.keylist[1];
Which doesn't work because the return of keylist[1] is a String? I did some research and the use of the window function was proposed. So I tried this:
window["data." + keylist[1]]();
Which leads to a "is not a function" error. What can I do to solve this problem?
As simple as that:
const mydata = data[ keylist[1] ];
Also, your code is correct from the point of syntax, but it tells completely different than you expect it to tell.
data.keylist[1];
tells JS that you expect to have an object called data which has a property called keylist and which is (most likely) type of array, and you want to get the second element of this array.
PS: And one more point here. Your question title is not completely correct because of the difference between Arrays and Object in JS.
There is no "string keys" for arrays in JS, so you cannot "access array with a string key". Well, truly speaking there are, but not for items of array. Array items only have numeric index, which you can use to access it. Objects, in contrast to arrays, may have named properties. So when you see something like that: data = myVar['data'], you can tell that you're dealing with an object, while data = someVar[0] can be both, an Array (most likely) or also an Object with key named '0'.
I don't think the issue you're having with your first example is because it returns a key. I believe the issue is because data doesn't have a property called keylist. Instead of that, try it as
data[keylist[1]]
and see if that works for you. The reason this one should work is that, in this situation, Javascript will evaluate the string return of keylist[1] and then use it as a string index for the data variable. Let me know if this works out for you :D
You can try using using something like this.
data[keylist[1]]

How do I access the 'str' value in my object?

I am trying to return the value under the key 'str' in an Object but I am having trouble accessing the value.
This is what is returned in the console:
Currently I am using a map function to go over the array and just return the _str value like so:
let idx = currentArray.map(function(x) {
return x._id._str;
});
However it is still returning the value as an object. How can I get just the value of the _str key?
Here is the full array without specifying the id field. This is what is returned if you jsut return 'x' in the map function.
You've clarified that the screenshot is of x._id. So to access _str, you'd use x._id[0]._str: The _str property is in the object referenced by the 0 property (the first entry in the array x._id refers to).
Note that in general, _-prefixed properties are meant not to be accessed by code outside the code responsible for the objects in question. You don't seem to be responsible for them, so accessing those properties is likely to make your code rely on undocumented properties that may change in the next "dot" release of whatever lib you're using. It's just convention, but it's a very common convention.
If you right click on the property, most browser consoles offer the ability to copy property path.
Based on this SO post and the docs, it appears that you can probably use x._id.str.
If I understand correctly, you are receiving the str value but it is an object instead of the string literal. In other words, you are getting _str: "598..." instead of "598....". A possible solution would be to use the mongo javascript function to convert the str value to a string.
In your case, I think something like return x._id.str; may work as _id is a MongoID.ObjectID.
I've also linked the documentation below for reference.
https://docs.mongodb.com/manual/reference/method/ObjectId/
Here's a relevant SO answer as well: Convert ObjectID (Mongodb) to String in JavaScript
I think you should write x[_id]._str because _id is one of the array objects.

Checking an empty object with lodash returns false

I have an object req.user.stripe that has a value of an empty object {}.
I would like to use the lodash function isEmpty() to check if this object is empty or not. When I run console.log(_.isEmpty(req.user.stripe)), I get a return value of false. console.log(req.user.stripe) in fact returns an empty object {}.
Not sure what I am missing. I am open to using a different method aside from lodash. Essentially, I need to access properties within req.user.stripe, but only if req.user.stripe is not an empty object (otherwise I'll get an error saying that JS cannot read property x on undefined).
Clarification
In my mongoose schema, when a user is created, they are created with a stripe parameter, but it defaults to an empty object {}. Only when we actually talk to stripe does that fill up with data. I have a number of beta users in my system that were given accounts, but not through the same process as someone registering on the frontend. These users are now required to pay, but they have to keep their accounts. I need to detect if a user has stripe information or not, hence why I am checking if the stripe parameter in the req.user object is or is not an empty object.
For example, if I want to access that last 4 digits of a user's saved card, I can access it this way req.user.stripe.customer.sources.data[0].last4. However, when trying to access a user without stripe data, an error similar to Cannot read property 'sources' of undefined. I need to be able to handle conditions like this when the req.user.stripe object is empty.
Before accessing that property use an if statement:
if(req.user && req.user.stripe) { do_your_thing() }
There's three options here:
Your object isn't actually empty, it just appears empty on the console for some reason.
It's actually empty when you do the console.log, but not when you do _.isEmpty (As suggested by #Todd Chaffee in the comments; but I find this doubtful)
There's a bug in _.isEmpty. (I also find this one doubtful, but it's a possibility)
But, as others have said in the comments, I don't think _.isEmpty is what you want in the first place.
To take your example of req.user.stripe.customer.sources.data[0].last4: what if req.user.stripe isn't empty, but customer isn't defined, or it's empty, or it's defined but the sources.data array is undefined or empty, or etc? Sure, maybe all of those situations are completely impossible in the current code, but will they always be? _.isEmpty(req.user.stripe) is a fairly fragile test.
A safer alternative is _.get(req, "user.stripe.customer.sources.data[0].last4"), which will just return null if any of those intermediary properties are null.
...but frankly it smells of a larger structure issue that you're trying to get the last4 digits of a credit card without knowing whether or not you've even got a customer in the first place.
This is an old question, but using _.isNil(object) solved this problem for me, returns if object is null or empty.

Backbone.js why do I have to use underscore (_.each) to target the model?

So whenever I want to select a model from my collection I always use backbone's very own where method.
var homeTeam = this.collection.where({teamName: this.currentTeamName('home')});
I have my own method that grabs the current team and I pass "home" or "away" as an argument, and it knows which model to grab, this is all fine and dandy, another example would be to just pass a string like below.
// This is practically the same as the above.
var homeTeam = this.collection.where({teamName: 'bulls'});
So if I log that variable console.log(homeTeam) the console shows that model, just like it does any model.
The console shows me I have access to regular methods a model can use http://backbonejs.org/#Model but if I call one of those methods I get an error, ex homeTeam.save({someAttr: 'juicy'});
So I just use underscore's each method like below, and it works.
_.each(homeTeam, function(model) { model.save({someAttr: 'juicy'}); }, this);
I have been doing this for awhile but I am curious to know why I must do that, when logging the homeTeam it passes the model just like
_.each(homeTeam, function(model) { console.log(model) }, this);
they show up exactly the same in the console.
Ahh, I think I see the problem here.
.where returns an Array; Even though it's an array of Model, the Javascript console will evaluate the entry as a model so you can see the methods that Backbone provides.
What you need to do is use .findWhere.
This will return the first matching model, as a correctly typed object.
Alternately you could try (just to prove) 'homeTeam[0].save(...)
To clarify: you're getting the error because homeTeam is not what you think it is; welcome to Javascript!
Because where returns an array of models. The array is not a model object. It's an array.
See source.
Assuming team.teamName is unique you could safely use .findWhere, which returns a single model from your collection instead of .find, which returns an array of models.
From the underscore docs:
findWhere
Looks through the list and returns the first value that matches all of the key-value pairs listed in properties.
as opposed to
where
Looks through each value in the list, returning an array of all the values that contain all of the key-value pairs listed in properties.

How is $('h1') logging to the web console as an array in jQuery?

If you do console.log($('some selector')) in the browser, it returns what looks like an array (first line):
But notice that it's not an instanceof Array, but it's actually the jQuery object.
When you do console.dir($('h1')), it shows it's actually the jQuery object.
The question is, how are they making it look like it's an array in the web console? I noticed in the jQuery source here they add reference to a few Array and Object methods, and here they add toArray (and slice and others) to the jQuery object. Is the web console somehow checking for these methods and if it finds one (toArray, indexOf, slice, etc.), it prints it as an Array? I would like to get this behavior out of any custom object, such as the Ember.ArrayProxy. Currently when you log the Ember.ArrayProxy it shows > Object or whatever, but it would be nice to show it as an array.
Any ideas?
You make your object inherit Array using the prototype, like so:
function SomeType() {
this.push(16);
}
SomeType.prototype = [];
SomeType.prototype.constructor = SomeType; // Make sure there are no unexpected results
console.log(new SomeType()); // Displays in console as [16]
And, of course, all jQuery objects are instances of the jQuery function/constructor, so that's how jQuery does it. As a bonus, because of the inheritance, you get all the methods from Array, and the indexing that comes with it too!

Categories