4

I'm developing with Angular and I have the following Typescript array of objects:

docs = [
    { 
        id: '1',
        type: {
            id: 1
            desc: 'Category 1',
        }
        title: 'Foo",
        date: '2018-06-21',
        attachments: [
            { id: 51, filename: 'foo.pdf', title: 'Foo' },
            { id: 20, filename: 'bar.doc', title: 'Bar' }
        ]
    },
    { 
        id: '2',
        type: {
            id: 2
            desc: 'Category 2',
        }
        title: 'Bar",
        date: '2018-06-21',
        attachments: [
            { id: 15, filename: 'foobar.xls', title: 'Foobar' },
            { id: 201, filename: 'example.doc', title: 'Example' }
        ]
    }
]

I need to get only a subset of the properties, something like this:

docs = [
    { 
        id: '1',
        type: {
            id: 1
            desc: 'Category 1',
        }
        attachments: [
            { id: 51 },
            { id: 20 }
        ]
    },
    { 
        id: '2',
        type: {
            id: 2
            desc: 'Category 2',
        }
        attachments: [
            { id: 15 },
            { id: 201 }
        ]
    }
]

How can I achieve this? Have I to create a parser or does exist any smart way (such as Lodash) to extract a lite version of the array?

3
  • Have a look at map Commented Jun 21, 2018 at 14:36
  • I have already seen it, but I cannot figure out how to map multiple properties: map = array.map(_ => _.x) Commented Jun 21, 2018 at 14:42
  • Just const result = docs.map(({ id, type, attachments }) => ({id, type, attachments: attachments.map(a => a.id)})); Commented Jun 21, 2018 at 14:53

5 Answers 5

4

var docs = [{"id":"1","type":{"id":1,"desc":"Category 1"},"title":"Foo","date":"2018-06-21","attachments":[{"id":51,"filename":"foo.pdf","title":"Foo"},{"id":20,"filename":"bar.doc","title":"Bar"}]},{"id":"2","type":{"id":2,"desc":"Category 2"},"title":"Bar","date":"2018-06-21","attachments":[{"id":15,"filename":"foobar.xls","title":"Foobar"},{"id":201,"filename":"example.doc","title":"Example"}]}];

const result = docs.map(({id,type,attachments})=>{
    let doc={id,type};
    doc.attachments=attachments.map(({id})=>({id}));
    return doc;
});

console.log(result);

have a look at this. this works perfectly!

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

2 Comments

Using the same mapping... what about if I would map only attachments with filename equals to example.doc?
attachments.map(({id})=>({id})); needs to be replaced by attachments.filter(att=>att.filename=='example.doc').map(({id})=>({id})); but keep in mind now attachments may be empty if there is no match found.
1

You can use array.map and object destructuring to extract only the wanted properties.

Also use JSON.parse and JSON.stringify to make a copy and avoid side effetcs.

docs2 = JSON.parse(JSON.stringify(docs)).map(
({id, type, attachements}) => 
  ({ id, 
    type,
    attachements: attachements.map(({id}) => ({id})
  })
)

2 Comments

Why the JSON.stringify?
I used JSON.stringify to make a deep copy of the object. Otherwise, a change of a property like "type.id" for example in the original "docs" will also change "type.id" in the copy. Otherwise you would have to manually copy the properties of "type". Both are valid solutions.
1

You can use Array.map with object spreading, something like this:

const mapSubset = ({ id, type, attachments }) => {
    return { id, type, attachments: attachments.map( {id} => id ) };
};

const subset = docs.map( mapSubset );

Comments

0

I was looking for a non-specific way to accomplish this or any other similar cases, so far I've thought of the following:

  • Have an IMapping<T> type, that defines the way to map each property.
  • Have an IMappingFunction<T> interface, that determines how to map a specific thing:

The following code demonstrates it:

type IMapping<T> = {
    [P in keyof T]: IMapping<T[P]> | IMappingFunction<T[P]>;
}

interface IMappingFunction<T>{
    (t: T): T | Partial<T>
}

class Person{
    name: string;
    lastName: string;
}

const obj: IMapping<Person> =  {
    name: s => s.toUpperCase(),
    lastName: s => s
}

function map<T>(obj: T, mapping: IMapping<T>) {
    return Object.keys(obj)
        .map(prop => { 
            const propMapping = mapping[prop];

            return {
                key: prop,
                value: typeof propMapping === 'function' ?
                    propMapping(obj[prop]) :
                    map(obj, propMapping)
            };
        })
        .reduce((acc, prop) => ({...acc, [prop.key]: prop.value}), { });
}

console.log(map({ name: 'Name', lastName: 'LastName'}, obj));

For a runnable snippet check here

Comments

-2

do you need to leave the original array intact? If not you can iterate through the list of objects using a for loop and use the 'delete' operator to delete the properties you no longer want.

For example:

var Employee = {
  firstname: "Mohammed",
  lastname: "Haddad"
}

delete Employee.firstname;

console.log(Employee);
// expected output: { lastname: "Haddad" }

2 Comments

I read that delete is very slow and not well to use... (the downvote it's not mine!)
I could be wrong, but I believe that only applies if you are using delete to remove elements from an array, not when you are using it to remove properties from an object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.