1

I have this JSON from Mongoose error catching on a NodeJS app with the express framework:

{
  "err": {
    "errors": {
      "last_name": {
        "message": "Path `last_name` is required.",
        "name": "ValidatorError",
        "properties": {
          "message": "Path `last_name` is required.",
          "type": "required",
          "path": "last_name"
        },
        "kind": "required",
        "path": "last_name"
      },
      "first_name": {
        "message": "Path `first_name` is required.",
        "name": "ValidatorError",
        "properties": {
          "message": "Path `first_name` is required.",
          "type": "required",
          "path": "first_name"
        },
        "kind": "required",
        "path": "first_name"
      },
      "password": {
        "message": "Path `password` (`iam`) is shorter than the minimum allowed length (6).",
        "name": "ValidatorError",
        "properties": {
          "message": "Path `password` (`iam`) is shorter than the minimum allowed length (6).",
          "type": "minlength",
          "minlength": 6,
          "path": "password",
          "value": "iam"
        },
        "kind": "minlength",
        "path": "password",
        "value": "iam"
      }
    },
    "_message": "User validation failed",
    "message": "User validation failed: last_name: Path `last_name` is required., first_name: Path `first_name` is required., password: Path `password` (`iam`) is shorter than the minimum allowed length (6).",
    "name": "ValidationError"
  }
}

How can I get the type and path of each error inside the properties, I have tried forEach() method but it didn't work, is there any other way to loop through this JSON?

Shidersz
  • 16,846
  • 2
  • 23
  • 48
Kadiem Alqazzaz
  • 554
  • 1
  • 7
  • 22
  • Possible duplicate of [How do I loop through or enumerate a JavaScript object?](https://stackoverflow.com/questions/684672/how-do-i-loop-through-or-enumerate-a-javascript-object) – kgrg May 19 '19 at 19:38
  • You can browse with Object.keys(). – Antoine Olivier May 19 '19 at 18:12

2 Answers2

1

Find the keys, the iterate over the keys. Add those results to some data structure.

I've chose to use map on the keys and added to an array.

const errors = {
      "err": {
        "errors": {
          "last_name": {
            "message": "Path `last_name` is required.",
            "name": "ValidatorError",
            "properties": {
              "message": "Path `last_name` is required.",
              "type": "required",
              "path": "last_name"
            },
            "kind": "required",
            "path": "last_name"
          },
          "first_name": {
            "message": "Path `first_name` is required.",
            "name": "ValidatorError",
            "properties": {
              "message": "Path `first_name` is required.",
              "type": "required",
              "path": "first_name"
            },
            "kind": "required",
            "path": "first_name"
          },
          "password": {
            "message": "Path `password` (`iam`) is shorter than the minimum allowed length (6).",
            "name": "ValidatorError",
            "properties": {
              "message": "Path `password` (`iam`) is shorter than the minimum allowed length (6).",
              "type": "minlength",
              "minlength": 6,
              "path": "password",
              "value": "iam"
            },
            "kind": "minlength",
            "path": "password",
            "value": "iam"
          }
        },
        "_message": "User validation failed",
        "message": "User validation failed: last_name: Path `last_name` is required., first_name: Path `first_name` is required., password: Path `password` (`iam`) is shorter than the minimum allowed length (6).",
        "name": "ValidationError"
      }
    }
 let output = Object.keys(errors.err.errors).map(key => { return {type:errors.err.errors[key].properties.type, path:errors.err.errors[key].properties.path} });
 console.log(output);
Randy Casburn
  • 13,840
  • 1
  • 16
  • 31
  • `map` returns an array. You do not need to first create `output =[]` and then pushing in the function. Just do `let output=Object.keys(errors.err.errors).map(key =>({type:errors.err.errors[key].properties.type, path:errors.err.errors[key].properties.path}))`. If you don't want the array, use `forEach` instead to iterate over the array. – some May 19 '19 at 18:36
  • You don't need to use `return` in the arrow-function, but since you are returning an object you must enclose it in parentheses (or it will be interpreted as a statement). `key => ({type:"error"})` works, `key => {type:"error"}` doesn't, `key => {return {type:"error"}}` works but is longer to type.. – some May 19 '19 at 18:44
1

Another alternative is to use for ... in to traverse the object properties of err.errors:

Example:

const input = {"err":{"errors":{"last_name":{"message":"Path `last_name` is required.","name":"ValidatorError","properties":{"message":"Path `last_name` is required.","type":"required","path":"last_name"},"kind":"required","path":"last_name"},"first_name":{"message":"Path `first_name` is required.","name":"ValidatorError","properties":{"message":"Path `first_name` is required.","type":"required","path":"first_name"},"kind":"required","path":"first_name"},"password":{"message":"Path `password` (`iam`) is shorter than the minimum allowed length (6).","name":"ValidatorError","properties":{"message":"Path `password` (`iam`) is shorter than the minimum allowed length (6).","type":"minlength","minlength":6,"path":"password","value":"iam"},"kind":"minlength","path":"password","value":"iam"}},"_message":"User validation failed","message":"User validation failed: last_name: Path `last_name` is required., first_name: Path `first_name` is required., password: Path `password` (`iam`) is shorter than the minimum allowed length (6).","name":"ValidationError"}};

for (const k in input.err.errors)
{
    const properties = input.err.errors[k].properties;
    console.log("Error for " + k);
    console.log("> Type: " + properties.type);
    console.log("> Path: " + properties.path);
    console.log("> Message: " + properties.message);
}
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Community
  • 1
  • 1
Shidersz
  • 16,846
  • 2
  • 23
  • 48
  • Better to use [for....of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) since for...in also gives you keys in the prototype chain. – some May 19 '19 at 18:48
  • @some But, to use `for ... of` I will have to do something like `for (k of Object.keys(input.err.errors))` since it won't work directly over the object. And in this case, whit an array of keys, I will prefer to use built-in array methods like shown on the other answer. – Shidersz May 19 '19 at 18:54
  • Use `for (const [key,value] of Object.entries(input.err.errors))` and instead of making lookups in `input.err.errors[k]` every time, use the variables key or value (or what you called them) – some May 19 '19 at 19:03
  • @some Ok, it is another alternative, but not what I have tried to show. I just tried to show how to traverse some object directly, not converting first to an array of `keys` or `entries`. – Shidersz May 19 '19 at 19:07
  • Look at your code. You use `input.err.errors[k]` twice. And you would have used it three times if you also printed the message. Every time you do `input.err.errors[k]` you make a lookup. At least save that as a constant for each iteration. `const value = input.err.errors[k]` instead of making the exact same lookup multiple times. It is not premature optimization. It is less to type, less chance to make a typo, easier to change if the path changes. – some May 19 '19 at 19:12