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?

2

2 Answers 2

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);

Sign up to request clarification or add additional context in comments.

2 Comments

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.
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..
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;}

5 Comments

Better to use for....of since for...in also gives you keys in the prototype chain.
@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.
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 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.
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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.