3

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.

Mike Hamilton
  • 1,519
  • 16
  • 24
  • 1
    Don't know what your problem is, but if `req.user.stripe` is an empty object (`{}`), and you try to access a property on it, you will **not** get a run-time error; you'll simply get `undefined`. –  Oct 31 '16 at 17:27
  • _.isEmpty on an empty object returns true, are you positive about testing it over an empty object? – acontell Oct 31 '16 at 17:43
  • The way you described this, _.isEmpty() should return true. Here is a working example http://jsfiddle.net/xwhan3zt/2/. Please provide a jsfiddle with it not working so we can better understand the details of why you are getting false. – Todd Chaffee Oct 31 '16 at 18:09
  • See my comment above. I initially gave the wrong link, but it's right now and you should be able to see that lodash is working as expected. – Todd Chaffee Oct 31 '16 at 18:14
  • JS fiddle doesn't produce the same results. I've updated my question with a little more clarification, hopefully that will help. – Mike Hamilton Oct 31 '16 at 18:36
  • Can you post a jsfiddle showing what you are seeing above? Without being able to repeat the problem it's difficult to understand why that could be happening. – Todd Chaffee Oct 31 '16 at 18:42
  • Here is a fork of yours with my notes http://jsfiddle.net/sroxt065/1/ – Mike Hamilton Oct 31 '16 at 18:46
  • That fork doesn't help a lot. I need to be able to reproduce the problem in order to debug it. Is it possible that something asynchronous is changing the value of `req.user.stripe` in between your two statements? – Todd Chaffee Oct 31 '16 at 18:55
  • That's the issue, I can't reproduce this in jsfiddle. This `req.user.stripe` value is set by mongoose at the time of user creation (and it's not a string of "{}" it actually is an empty object that is being set) – Mike Hamilton Oct 31 '16 at 19:01
  • Also, `console.log` sometimes only stores a reference to an object or does lazy evaluation. So it is possible that when you are looking at the output in the console, it is an updated value of the object, rather than the value of the object at the time you ran `console.log`. Try `console.log(JSON.stringify(req.user.stripe))` to see if that makes a difference. – Todd Chaffee Oct 31 '16 at 19:07
  • See this question for more explanation about how console.log can sometimes be misleading. http://stackoverflow.com/questions/7389069/console-log-object-at-current-state – Todd Chaffee Oct 31 '16 at 19:13
  • When you do req.user.stripe.toString() of your object, what does the console output? Does your object have a length property? Another suggestion is making your own isEmpty method and just checking if the object has a certain property (or properties) that you're interested in. Anyhow, I'd like to know why _.isEmpty is not working for you – acontell Oct 31 '16 at 19:44
  • Try `for(var key in req.user.stripe) { if(req.user.stripe.hasOwnProperty(key)) { console.log("Not empty: " + key) } }`. That's basically the logic that the `_.isEmpty` function uses. – Retsam Nov 02 '16 at 19:24

3 Answers3

0

Before accessing that property use an if statement:

if(req.user && req.user.stripe) { do_your_thing() }
João Vilaça
  • 601
  • 1
  • 6
  • 13
  • But why is `_.isEmpty` returning false on an empty object? –  Oct 31 '16 at 17:25
  • because it's not null, it's an empty object lol. i know right? https://lodash.com/docs/4.16.4#isEmpty – João Vilaça Oct 31 '16 at 17:27
  • That's not what I understand from reading the docs. It should return true if the object is empty... – Mike Hamilton Oct 31 '16 at 17:41
  • I also understand it that way, but that's not how it works so...the safest way is the use the if approach. First checking if req.user has data inside, and then if it does, check if req.user.strip has data inside. :) – João Vilaça Oct 31 '16 at 17:44
  • `req.user` will always have data inside. The issues is more so if `req.user.stripe.sources` or some other nested property has data. – Mike Hamilton Oct 31 '16 at 18:02
  • then i think you should use a specific if for each of those cases, it's safer. – João Vilaça Oct 31 '16 at 18:08
  • so what your telling me is there isn't a more elegant solution than a set of if statements nested 5 or more levels deep? – Mike Hamilton Oct 31 '16 at 18:35
  • No, but it works for your purpose. And if you want everything clean you can make an auxiliary method for that purpose. But the most important thing is that it works – João Vilaça Oct 31 '16 at 19:21
  • _isEmpty does work for empty objects, that's what it was made for. Most likely your object has enumerable properties that are not visible when you do console.log – Overdrivr Jan 21 '18 at 14:16
0

There's three options here:

  1. Your object isn't actually empty, it just appears empty on the console for some reason.

  2. 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)

  3. 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.

Retsam
  • 30,909
  • 11
  • 68
  • 90
0

This is an old question, but using _.isNil(object) solved this problem for me, returns if object is null or empty.

A.Blanc
  • 403
  • 1
  • 6
  • 15