Petter Östergren
Petter Östergren

Reputation: 1013

Lodash: filter then map over an object

Im trying to filter out objects with a delete: false to then only map and render this objects to screen but I'm not sure how to get it to work.

Sample object

{
  "8xf0y6ziyjabvozdd253nd": {
    "id": "8xf0y6ziyjabvozdd253nd",
    "timestamp": 1467166872634,
    "title": "Udacity is the best place to learn React",
    "body": "Everyone says so after all.",
    "author": "thingtwo",
    "category": "react",
    "voteScore": 6,
    "deleted": false
  }
}

Method for finding key and map.

const {posts} = this.props
        return _.find(posts, { 'deleted': false })_.map(posts, post => {
            return (
                <div key={post.id}>

Upvotes: 7

Views: 26868

Answers (5)

Koushik Chatterjee
Koushik Chatterjee

Reputation: 4175

Basically, you can apply lodash#reduce to Object directly instead of getting all the keys first, and then iterating again. And with reduce you can do the map and filtering together.

_.reduce(obj, (i, v, k)=> !v.deleted && !(i[k] = v) || i, {});

Let's create a working example for you, Here is a code snippet:

var obj = {
  "9ny0z4ziyjabvozdc713dr": {
    "id": "9ny0z4ziyjabvozdc713dr",
    "timestamp": 1467166879723,
    "title": "StackOverfow is the best place to learn Angular",
    "body": "bla bla bla bla.",
    "author": "myself",
    "category": "angular",
    "voteScore": 9,
    "deleted": true
  },
    "8xf0y6ziyjabvozdd253nd": {
    "id": "8xf0y6ziyjabvozdd253nd",
    "timestamp": 1467166872634,
    "title": "Udacity is the best place to learn React",
    "body": "Everyone says so after all.",
    "author": "thingtwo",
    "category": "react",
    "voteScore": 6,
    "deleted": false
  }
}

var finalObj =_.reduce(obj, (i, v, k)=> !v.deleted && !(i[k] = v) || i, {});

console.log(finalObj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

EDIT

For the specific case (of OP), just some key/value pair needs to be removed and construct a new object, then better to use lodash#omitBy to simply remove some entries from an object against some condition. Here is a simple example of this particular use.

_.omitBy(obj, o=>o.deleted);

Here is the code snippet for this example:

var obj = {
      "9ny0z4ziyjabvozdc713dr": {
        "id": "9ny0z4ziyjabvozdc713dr",
        "timestamp": 1467166879723,
        "title": "StackOverfow is the best place to learn Angular",
        "body": "bla bla bla bla.",
        "author": "myself",
        "category": "angular",
        "voteScore": 9,
        "deleted": true
      },
        "8xf0y6ziyjabvozdd253nd": {
        "id": "8xf0y6ziyjabvozdd253nd",
        "timestamp": 1467166872634,
        "title": "Udacity is the best place to learn React",
        "body": "Everyone says so after all.",
        "author": "thingtwo",
        "category": "react",
        "voteScore": 6,
        "deleted": false
      }
    }

    var finalObj =_.omitBy(obj, o=>o.deleted);

    console.log(finalObj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

However, If any transformation needed in between (Array or Object), or the output type needs to be customized then I will still prefer to suggest to use reduce.

Upvotes: 8

SALEH
SALEH

Reputation: 1562

If you want to skip lodash, the native API of javascript array will offer you a solution like the following:

const { posts } = this.props;

return posts
    .find(post => !post.deleted)
    .map(post => {
        return (
            <div key={post.id}>...

Upvotes: 1

Guillermo Moratorio
Guillermo Moratorio

Reputation: 662

If you want to filter, the easiest thing to use is an actual filter. I'm not very familiar with React, but the Lodash chain below will work, if React supports more complex chains.

I noticed you have a nested object, if that is intentional, then the code below will do the trick:

// I added some fake posts to make the data more illustrative 

let posts = [{
    "8xf0y6ziyjabvozdd253nd": {
        "id": "8xf0y6ziyjabvozdd253nd",
        "timestamp": 1467166872634,
        "title": "Udacity is the best place to learn React",
        "body": "Everyone says so after all.",
        "author": "thingtwo",
        "category": "react",
        "voteScore": 6,
        "deleted": false
    }
}, {
    "8888ziyjabvozdd253nd": {
        "id": "8888ziyjabvozdd253nd",
        "timestamp": 1467166872634,
        "title": "Udacity is the best place to learn React",
        "body": "Everyone says so after all.",
        "author": "thingtwo",
        "category": "react",
        "voteScore": 6,
        "deleted": true
    }
}, {
    "77776ziyjabvozdd253nd": {
        "id": "77776ziyjabvozdd253nd",
        "timestamp": 1467166872634,
        "title": "Udacity is the best place to learn React",
        "body": "Everyone says so after all.",
        "author": "thingtwo",
        "category": "react",
        "voteScore": 6,
        "deleted": false
    }
}, {
    "6666ziyjabvozdd253nd": {
        "id": "6666ziyjabvozdd253nd",
        "timestamp": 1467166872634,
        "title": "Udacity is the best place to learn React",
        "body": "Everyone says so after all.",
        "author": "thingtwo",
        "category": "react",
        "voteScore": 6,
        "deleted": true
    }
}, {
    "55556ziyjabvozdd253nd": {
        "id": "55556ziyjabvozdd253nd",
        "timestamp": 1467166872634,
        "title": "Udacity is the best place to learn React",
        "body": "Everyone says so after all.",
        "author": "thingtwo",
        "category": "react",
        "voteScore": 6,
        "deleted": false
    }
}];

// you'd just return _(posts) here directly, but I'm assigning a variable so we can show the console log for this snippet
const filteredPosts = _(posts)
    .filter(post => {
        const objectKey = Object.keys(post)[0];
        const innerData = post[objectKey];
        return innerData.deleted === false
    })
    .map(post => {
        const objectKey = Object.keys(post)[0];
        // your return would be in the format of <div key={objectKey}>
      return  `<div key={${objectKey}}>`
    })
    .valueOf();




console.log(filteredPosts);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

If the nesting of the object isn't intentional, then getting the info will be more straightforward and cleaner. If your actual objects look like the sample ones I have below, you could access the data like this:

let posts = [{
        "id": "8xf0y6ziyjabvozdd253nd",
        "timestamp": 1467166872634,
        "title": "Udacity is the best place to learn React",
        "body": "Everyone says so after all.",
        "author": "thingtwo",
        "category": "react",
        "voteScore": 6,
        "deleted": false
}, {
        "id": "8888ziyjabvozdd253nd",
        "timestamp": 1467166872634,
        "title": "Udacity is the best place to learn React",
        "body": "Everyone says so after all.",
        "author": "thingtwo",
        "category": "react",
        "voteScore": 6,
        "deleted": true
}, {
        "id": "77776ziyjabvozdd253nd",
        "timestamp": 1467166872634,
        "title": "Udacity is the best place to learn React",
        "body": "Everyone says so after all.",
        "author": "thingtwo",
        "category": "react",
        "voteScore": 6,
        "deleted": false
}];

// you'd just return _(posts) here directly, but I'm assigning a variable so we can show the console log for this snippet
const filteredPosts = _(posts)
    .filter(post => {
        return post.deleted === false
    })
    .map(post => {
        // your return would be in the format of <div key={post.id}>
      return  `<div key={${post.id}}>`
    })
    .valueOf();




console.log(filteredPosts);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

Upvotes: 2

marvel308
marvel308

Reputation: 10458

you can do that in the following way

let obj = {
  "8xf0y6ziyjabvozdd253nd": {
    "id": "8xf0y6ziyjabvozdd253nd",
    "timestamp": 1467166872634,
    "title": "Udacity is the best place to learn React",
    "body": "Everyone says so after all.",
    "author": "thingtwo",
    "category": "react",
    "voteScore": 6,
    "deleted": false
  }
}

let result = Object.keys(obj).reduce((a, b) =>{
    if(obj[b].deleted != false){
        a[b] = obj[b];
    }
    return a;
}, {});

console.log(result);

Upvotes: 0

Dekel
Dekel

Reputation: 62556

The result of _.find is an array, so if you want to map the elements in that array you should _.map(result)

const {posts} = this.props;
return _.map(_.find(posts, { 'deleted': false }), post => {
            return (
                <div key={post.id}>

Upvotes: 1

Related Questions