how to filter array of object and nested of array

2020-05-09 18:52发布

问题:

I have two arrays of nested objects. I want to filter data based on permissionObj.

This is coming from database. Here are arrays of sub-arrays in the permissionObj.

I need to do another condition in reduce function . For example , if Pubsidebar value is token is public, I want to keep static content {label: "test",value: "public"} without filtering with permissionObj and if other key and value is match with permissionObj,then it will be push inside token .

    let permissionObj = [
      {
        'OA deal': [
          {
            label: 'can view',
            value: 'can_view',
          },
        ],
      },


      {
        Deposit: [
          {
            label: 'can_view',
            value: 'can_view',
          },
        ],
      },

      {
        Journals: [
          {
            label: 'can create',
            value: 'can_create',
          },
        ],
      },
      {
        Dashboard: [
          {
            label: 'can view',
            value: 'can_view',
          },
        ],
      },
      {
        token: [
          {
            label: 'can view',
            value: 'can_create',
          },
        ],
      },
    ]

    const PubSidebar = [
      {
        label: 'Dashboard',
        value: 'can_view',
      },{
        label: 'transction',
value:"public",content:[{label:"test2",value:"public"}]

},
      {
        label: 'token',
        value: 'public',
        content: [
          {
            key: 'token',
            value: 'can_create',
          },
          {
            key: 'test',
            value: 'public',
          },
        ],
      },
      {
        label: 'OA deal',
        content: [
          {
            label: 'view oadeal',
            key: 'OA deal',
            value: 'can_view',
          },

          {
            label: 'Deposit',
            key: 'Deposit',
            value: 'can_view',
          },
          {
            label: 'Corrections',
            key: 'Corrections',
            value: 'can_edit',
          },
        ],
      },
      {
        label: 'Journals',
        content: [
          {
            label: 'Add Journal',
            key: 'Journals',
            value: 'can_create',
          },
        ],
      },
    ]

    const filterObject = permissionObj.reduce((a, c) => {
      for (const key in c) {
        a[key] = c[key]
      }
      return a
    }, {})
    const result = PubSidebar.reduce((a, c) => {
      if (
        filterObject[c.label] &&
        c.value &&
        filterObject[c.label].some(s => s.value === c.value)
      ) {
        a.push(c)
      } else if (c.value === 'public' && c.label === 'token') {
        if (
          (c.content = c.content.filter(
            f =>
              filterObject[f.key] &&
              filterObject[f.key].some(s => s.value == f.value)
          ))
        ) {
          c.content = c.content.filter(
            f =>
              filterObject[f.key] &&
              filterObject[f.key].some(s => s.value == f.value)
          )
          a.push(c)
        }
      } else if (c.content.some(s => filterObject[s.key]) && c.content) {
        c.content = c.content.filter(
          f =>
            filterObject[f.key] && filterObject[f.key].some(s => s.value == f.value)
        )
        a.push(c)
      }

      return a
    }, [])

    console.log(result)

I am trying to getting public data from sidebar without filtering with permissionObj.

my expected output would :

    [
      {
        "label": "Dashboard",
        "value": "can_view"
      },
{
            label: 'transction',
    value:"public",content:[{label:"test2",value:"public"}]

    },
      {
        "label": "token",
        "value": "public",
        "content": [{
            "key": "test",
            "value": "public"
          }
          {
            "key": "token",
            "value": "can_create"
          }
        ]
      },
      {
        "label": "OA deal",
        "content": [
          {
            "label": "view oadeal",
            "key": "OA deal",
            "value": "can_view"
          },
          {
            "label": "Deposit",
            "key": "Deposit",
            "value": "can_view"
          }
        ]
      },
      {
        "label": "Journals",
        "content": [
          {
            "label": "Add Journal",
            "key": "Journals",
            "value": "can_create"
          }
        ]
      }
    ]

回答1:

You can add a condition inside of reduce method and your content property will not be filtered:

if (c.value ==='public' && c.content.some(f => filterObject[f.key] && 
    filterObject[f.key].some(s => s.value == f.value))) {
        a.push(c);
}

And try to avoid filter your data inside of if condition.

So the code would look like this:

let permissionObj = [
  {
    'OA deal': [
      {
        label: 'can view',
        value: 'can_view',
      },
    ],
  },

  {
    Deposit: [
      {
        label: 'can_view',
        value: 'can_view',
      },
    ],
  },

  {
    Journals: [
      {
        label: 'can create',
        value: 'can_create',
      },
    ],
  },
  {
    Dashboard: [
      {
        label: 'can view',
        value: 'can_view',
      },
    ],
  },
  {
    token: [
      {
        label: 'can view',
        value: 'can_create',
      },
    ],
  },
]

const PubSidebar = [
  {
    label: 'Dashboard',
    value: 'can_view',
  },
  {
    label: 'token',
    value: 'public',
    content: [
      {
        key: 'token',
        value: 'can_create',
      },
      {
        key: 'test',
        value: 'public',
      },
    ],
  },
  {
    label: 'OA deal',
    content: [
      {
        label: 'view oadeal',
        key: 'OA deal',
        value: 'can_view',
      },

      {
        label: 'Deposit',
        key: 'Deposit',
        value: 'can_view',
      },
      {
        label: 'Corrections',
        key: 'Corrections',
        value: 'can_edit',
      },
    ],
  },
  {
    label: 'Journals',
    content: [
      {
        label: 'Add Journal',
        key: 'Journals',
        value: 'can_create',
      },
    ],
  },
]



const filterObject = permissionObj.reduce((a, c) => {
  for (const key in c) {
    a[key] = c[key]
  }
  return a
}, {})




const result = PubSidebar.reduce((a, c) => {
  if (filterObject[c.label] && c.value && filterObject[c.label].some(s => s.value === c.value)) {
      a.push(c)
  } else if (c.value === 'public' && c.label === 'token') {
      if (c.value ==='public' && c.content.some(f => filterObject[f.key] && filterObject[f.key].some(s => s.value == f.value))) {
          a.push(c);
      }
      else {
          c.content = c.content.filter(f => filterObject[f.key]
              &&  filterObject[f.key].some(s => s.value == f.value));
          a.push(c);
      }
  } else if (c.content.some(s => filterObject[s.key]) && c.content) {
      c.content = c.content.filter(
        f =>
          filterObject[f.key] && filterObject[f.key].some(s => s.value == f.value)
      )
      a.push(c)
  }

  return a
}, [])

console.log(result)



回答2:

I tried this with the object you provided in the question (permissionObj)

permissionObj.map( 
  p =>{  
    return { 
      label: Object.keys(p)[0], value:p[Object.keys(p)[0]][0].value 
    }
  }
)

which walks the keys, and take the first as the label and its first sub array object to get the value

resulting in this:

[{"label":"OA deal","value":"can_view"},{"label":"Deposit","value":"can_view"},{"label":"Journals","value":"can_create"},{"label":"Dashboard","value":"can_view"},{"label":"token","value":"can_create"}]

some of the data you required isnt in the permissionObj so I cannot add that - as i dont know where that comes from