{"action":"created","issue":{"url":"https://api.github.com/repos/HeyImAlex/reselect-map/issues/1","repository_url":"https://api.github.com/repos/HeyImAlex/reselect-map","labels_url":"https://api.github.com/repos/HeyImAlex/reselect-map/issues/1/labels{/name}","comments_url":"https://api.github.com/repos/HeyImAlex/reselect-map/issues/1/comments","events_url":"https://api.github.com/repos/HeyImAlex/reselect-map/issues/1/events","html_url":"https://github.com/HeyImAlex/reselect-map/issues/1","id":159715128,"number":1,"title":"Complex transformations","user":{"login":"avanderhoorn","id":585619,"avatar_url":"https://avatars.githubusercontent.com/u/585619?v=3","gravatar_id":"","url":"https://api.github.com/users/avanderhoorn","html_url":"https://github.com/avanderhoorn","followers_url":"https://api.github.com/users/avanderhoorn/followers","following_url":"https://api.github.com/users/avanderhoorn/following{/other_user}","gists_url":"https://api.github.com/users/avanderhoorn/gists{/gist_id}","starred_url":"https://api.github.com/users/avanderhoorn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/avanderhoorn/subscriptions","organizations_url":"https://api.github.com/users/avanderhoorn/orgs","repos_url":"https://api.github.com/users/avanderhoorn/repos","events_url":"https://api.github.com/users/avanderhoorn/events{/privacy}","received_events_url":"https://api.github.com/users/avanderhoorn/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2016-06-10T20:21:47Z","updated_at":"2016-06-10T22:34:59Z","closed_at":null,"body":"I currently have a reducer which looks something like the following:\r\n```\r\nconst initialState = { \r\n    listing: [],\r\n    byId: {},\r\n    byContextId: {},\r\n    filteredIds: [],\r\n    filters: {},\r\n    selectedContextId: null,\r\n    selectedContext: null\r\n}\r\n\r\nexport default function messages(state = initialState, action) {\r\n    if (action.type == MESSAGES_RECEIVED_BATCH || action.type == MESSAGES_RECEIVED_ITEM) { \r\n        console.time(`[PERF] ${MESSAGES_RECEIVED_BATCH}`);\r\n\r\n        let listing = state.listing;\r\n        let byId = state.byId;\r\n        let byContextId = state.byContextId;\r\n \r\n        // sometimes I can get messages sent which I already have\r\n        const newListing = [];\r\n        action.messages.forEach(message => {\r\n            if (!state.byId[message.id]) {\r\n                newListing.push(message);\r\n            }\r\n        });\r\n\r\n        if (newListing.length > 0) {\r\n            // - index messages by id\r\n            // - group messages by context id (with nested list and sub grouping by type)\r\n            // - store messages in array\r\n\r\n            let newById = {};\r\n            let newByContextId = {};\r\n            newListing.forEach(message => {\r\n                const context = newByContextId[message.context.id] || { listing: [], byType: {} };\r\n                message.types.forEach(type => {\r\n                    context.byType[type] = context.byType[type] || [];\r\n                    context.byType[type].push(message);\r\n                });\r\n                context.listing.push(message);\r\n\r\n                newByContextId[message.context.id] = context;\r\n                newById[message.id] = message;\r\n            });\r\n            for (var contextId in byContextId) {\r\n                const context = byContextId[contextId];\r\n                const newContext = newByContextId[contextId];\r\n                if (newContext) {\r\n                    newContext.listing.push(...context.listing);\r\n                    Object.assign(newContext.byType, context.byType);\r\n                }\r\n                else {\r\n                    newByContextId[contextId] = context;\r\n                }\r\n            }\r\n            byContextId = newByContextId;\r\n            byId = Object.assign(newById, state.byId);\r\n\r\n            newListing.push(listing);\r\n            listing = newListing;\r\n\r\n        }\r\n\r\n        ....\r\n\r\n        console.timeEnd(`[PERF] ${MESSAGES_RECEIVED_BATCH}`);\r\n\r\n        return {\r\n            ...state,\r\n            listing,\r\n            byId,\r\n            byContextId,\r\n            filteredIds,\r\n            selectedContext\r\n        };\r\n    }\r\n    else if (action.type == MESSAGES_REQUESTED_ITEM) {\r\n        return {\r\n            ...state,\r\n            selectedContextId: action.contextId,\r\n            selectedContext: state.byContextId[action.contextId]\r\n        }\r\n    }\r\n    return state;\r\n}\r\n```\r\n\r\nTo help paint a picture of what the above is doing, the following is the type of data I have and the structures that I'm trying to have \"access\" to (note, it's more complex than this but trying to simply things):\r\n```\r\n// input\r\naction.messages = [\r\n    { id: 1, context: { id: 1, ... }, types: [ 'a', 'b' ], payload: { ... } }, \r\n    { id: 2, context: { id: 2, ... }, types: [ 'c' ], payload: { ... } }, \r\n    { id: 3, context: { id: 1, ... }, types: [ 'a' ], payload: { ... } }, \r\n    { id: 4, context: { id: 1, ... }, types: [ 'c' ], payload: { ... } }, \r\n    { id: 5, context: { id: 1, ... }, types: [ 'd' ], payload: { ... } }, \r\n    { id: 6, context: { id: 2, ... }, types: [ 'c' ], payload: { ... } }, \r\n    { id: 7, context: { id: 2, ... }, types: [ 'a' ], payload: { ... } }, \r\n];\r\n\r\n// output\r\nstate = {\r\n    listing: [ ... ], // Simple: Unique list of messages by message.id\r\n    byId: { ... },   // Simple: Indexed messages by message.id\r\n    byContextId: {\r\n        1: {\r\n            listing: [ ... ], // Unique list of messages by message.id where context.id = 1\r\n            byType: {\r\n                'a': [ .... ], // Unique list of messages by message.id where message.context.id = 1 and message.type = 'a'\r\n                'b': [ .... ], // Unique list of messages by message.id where message.context.id = 1 and message.type = 'b'\r\n                ...\r\n            },\r\n            ... // others here\r\n        }\r\n    }, // Harder: Grouped by message.context.id\r\n    ...\r\n}\r\n```\r\n\r\nAs you can see there are some complex but not extraordinary stuff going on here. There is also a lot which shouldn't be here and should be in selector. \r\n\r\nNow, given the relative complexity of the transformation and number of messages that are being dealt with (range 500-5000), I'm keen not to have to recalculate everything each time I get a new message come in (which I'm currently defending against and selectors don't do out of the box). In thinking about shifting this logic into selectors, I'm trying to figure out how I'm best to only recalculate what has actually been affected... hence how I came across `reselect-map`.\r\n\r\nWhen looking at the API I'm left wondering if there is currently support for my needs? What I'm thinking I need is a way to describe how the data should be \"keyed\"... In my case I would say that the key for `byContextId` is at `message.context.id`... then `reselect-map` would only make me recalculate the state for the contextIds that where received in received batch of messages and remember the state of the rest.\r\n\r\nAny thoughts on how I should do this or I'm thinking about this incorrectly, etc. "},"comment":{"url":"https://api.github.com/repos/HeyImAlex/reselect-map/issues/comments/225312062","html_url":"https://github.com/HeyImAlex/reselect-map/issues/1#issuecomment-225312062","issue_url":"https://api.github.com/repos/HeyImAlex/reselect-map/issues/1","id":225312062,"user":{"login":"avanderhoorn","id":585619,"avatar_url":"https://avatars.githubusercontent.com/u/585619?v=3","gravatar_id":"","url":"https://api.github.com/users/avanderhoorn","html_url":"https://github.com/avanderhoorn","followers_url":"https://api.github.com/users/avanderhoorn/followers","following_url":"https://api.github.com/users/avanderhoorn/following{/other_user}","gists_url":"https://api.github.com/users/avanderhoorn/gists{/gist_id}","starred_url":"https://api.github.com/users/avanderhoorn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/avanderhoorn/subscriptions","organizations_url":"https://api.github.com/users/avanderhoorn/orgs","repos_url":"https://api.github.com/users/avanderhoorn/repos","events_url":"https://api.github.com/users/avanderhoorn/events{/privacy}","received_events_url":"https://api.github.com/users/avanderhoorn/received_events","type":"User","site_admin":false},"created_at":"2016-06-10T22:34:59Z","updated_at":"2016-06-10T22:34:59Z","body":"Once you have the previous state, you could assert that the next thing you need is knowing what changed from the last run to this run. "}}
{"actor":{"display_login":"avanderhoorn"}}