GuyWithGlasses
GuyWithGlasses

Reputation: 51

Having trouble using GroupBy with lodash trying to format my array correctly

I want to take a list of users and categorize them in a new array to be rendered by my app.

What I am given:

OnlineList = [
  {
    "Role": "Adjuster",
    "AccountId": "4",
    "UserId": "1e72d58e",
    "DisplayName": "Big Bob",
  },
  {
    "Role": "Adviser",
    "AccountId": "5",
    "UserId": "a0daba73",
    "DisplayName": "Sassy Sally",
  }
];

What result I want:

OnlineUsers = {
  "Dealership": [
    {
      "Role": "Adviser",
      "AccountId": "Dealership",
      "UserId": "a0daba73",
      "DisplayName": "Sassy Sally",
    }
  ],
  "ClaimsCo": [
    {
      "Role": "Adjuster",
     "AccountId": "ClaimsCo",
      "UserId": "1e72d58e",
      "DisplayName": "Big Bob",
    }
  ]
}

Result I get:

OnlineUsers = {
  "5": [    <----------- Problem
    {
      "Role": "Adviser",
      "AccountId": "5",   <----------- Problem
      "UserId": "a0daba73",
      "DisplayName": "Sassy Sally",
    }
  ],
  "ClaimsCo": [
    {
      "Role": "Adjuster",
      "AccountId": "Dealership",
      "UserId": "1e72d58e",
      "DisplayName": "Big Bob",
    }
  ]
}

Here is a JFiddle I set up replicating the problem: http://jsfiddle.net/vc4mjwx3/20/

My code:

// loaded from API Request into array
var OnlineList = [];
//  Sorted and ordered for display
var OnlineUsers = [];
OnlineList = [
  {
    "Role": "Adjuster",
    "AccountId": "4",
    "UserId": "1e72d58e",
    "DisplayName": "Big Bob",
  },
  {
    "Role": "Adviser",
    "AccountId": "5",
    "UserId": "a0daba73",
    "DisplayName": "Sassy Sally",
  }
];

// GroupBy function: https://stackoverflow.com/questions/14446511/most-efficient-method-to-groupby-on-an-array-of-objects/43215522
let groupBy = function(xs, key) {
	return xs.reduce(function(rv, x) {
      (rv[x[key]] = rv[x[key]] || []).push(x);
      return rv;
  }, {});
};

// Simulates a get by Id API service
let accountService = (id) => {
	if (id == 4) {
  return "ClaimsCo."
  }
 	else  {
  return "Dealership"
  }
}

// pass in AccountId
let getAccountName = function(int) {
  var accountName = "";
  //get AccountName from Id
  accountName = accountService(int);
    for(var x=0; x < OnlineList.length; x++){
    // check for AccountId
      if(OnlineList[x].hasOwnProperty('AccountId')){
      // Set AccountId value to AccountName
      OnlineList[x].AccountId = accountName;
      // Group results and set to OnlineUsers array
      OnlineUsers = groupBy(OnlineList, 'AccountId');
      break;
     }
	}
};

// Go into first element of array and get AccountId value
var id = _.get(OnlineList[0], "AccountId");
// Convert value to int
var int = parseInt(id,10);
// Pass into function that gets AccountName from AccountId and replaces AccountId in that element of OnlineList array
getAccountName(int);

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

Overall I want my code to function like this:

  1. Iterate over each element in the OnlineList
  2. For that element, grab the AccountId value
  3. Pass that AccountId value into a service that will return an AccountName
  4. Replace the AccountId of that element with the AccountName
  5. repeat for all other elements in OnlineList array
  6. After all AccountId/AccountName are handled, use GroupBy to group all elements of the OnlineList array by AccountId property and set them to a new array called OnlineUsers.

Upvotes: 1

Views: 110

Answers (3)

Ghassen Rjab
Ghassen Rjab

Reputation: 713

The question has been answered but I have a different solution I would like to share.

I recently created a library that does array categorization in JavaScript, called categorize.

Here is what would be the solution using it:

const { categorize } = require("categorize");    

const onlineList = [
  {
    "Role": "Adjuster",
    "AccountId": "4",
    "UserId": "1e72d58e",
    "DisplayName": "Big Bob",
  },
  {
    "Role": "Adviser",
    "AccountId": "5",
    "UserId": "a0daba73",
    "DisplayName": "Sassy Sally",
  }
];

const categories = [
  { name: "Dealership", filter: ({ AccountId }) => AccountId === "4" },
  { name: "ClaimsCo", filter: ({ AccountId }) => AccountId === "5" },
];

const onlineUsers = categorize(onlineList, categories);

The onlineUsers variable will contain this object:

{
  "Dealership": [
    {
      "Role": "Adjuster",
      "AccountId": "4",
      "UserId": "1e72d58e",
      "DisplayName": "Big Bob"
    }
  ],
  "ClaimsCo": [
    {
      "Role": "Adviser",
      "AccountId": "5",
      "UserId": "a0daba73",
      "DisplayName": "Sassy Sally"
    }
  ]
}

Upvotes: 1

Ori Drori
Ori Drori

Reputation: 192287

You need to map and replace AccountId number with the name, and then group by the name. I use _.flow() to create a pipeline:

const { flow, partialRight: pr, map, groupBy } = _;

// Simulates a get by Id API service
const accountService = (id) => id === 4 ? "ClaimsCo." : "Dealership";

const fn = flow(
  pr(map, o => ({ ...o, AccountId: accountService(+o.AccountId) })), // replace AccountId with name the + operator converts to number
  pr(groupBy, 'AccountId'), // group by the new AccountId
)

const OnlineList = [{"Role":"Adjuster","AccountId":"4","UserId":"1e72d58e","DisplayName":"Big Bob"},{"Role":"Adviser","AccountId":"5","UserId":"a0daba73","DisplayName":"Sassy Sally"}];

//result
const OnlineUsers = fn(OnlineList);

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

And the terser version using lodash/fp:

const { flow, map, groupBy } = _;

// Simulates a get by Id API service
const accountService = (id) => id === 4 ? "ClaimsCo." : "Dealership";

const fn = flow(
  map(o => ({ ...o, AccountId: accountService(+o.AccountId) })), // replace AccountId with name the + operator converts to number
  groupBy('AccountId'), // group by the new AccountId
)

const OnlineList = [{"Role":"Adjuster","AccountId":"4","UserId":"1e72d58e","DisplayName":"Big Bob"},{"Role":"Adviser","AccountId":"5","UserId":"a0daba73","DisplayName":"Sassy Sally"}];

//result
const OnlineUsers = fn(OnlineList);

console.log(OnlineUsers);
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>

Upvotes: 1

GuyWithGlasses
GuyWithGlasses

Reputation: 51

    // loaded from API Request into array
var OnlineList = [];
//  Sorted and ordered for display
var OnlineUsers = [];
OnlineList = [{
    "Role": "Adjuster",
    "AccountId": "4",
    "UserId": "1e72d58e",
    "DisplayName": "Big Bob",
  },
  {
    "Role": "Adviser",
    "AccountId": "5",
    "UserId": "a0daba73",
    "DisplayName": "Sassy Sally",
  }
];

// GroupBy function: https://stackoverflow.com/questions/14446511/most-efficient-method-to-groupby-on-an-array-of-objects/43215522
let groupBy = function(xs, key) {
  return xs.reduce(function(rv, x) {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
  }, {});
};

// Simulates a get by Id API service
let accountService = (id) => {
  if (id == 4) {
    return "ClaimsCo."
  } else {
    return "Dealership"
  }
}

// pass in AccountId
let getAccountName = function(int, element) {
  var accountName = "";
  //get AccountName from Id
  accountName = accountService(int);
  // check for AccountId
  if (OnlineList[element].hasOwnProperty('AccountId')) {
    // Set AccountId value to AccountName
    OnlineList[element].AccountId = accountName;
    // Group results and set to OnlineUsers array
    OnlineUsers = groupBy(OnlineList, 'AccountId');
  }
};

for (var x = 0; x < OnlineList.length; x++) {
  var id = _.get(OnlineList[x], "AccountId");
  var int = parseInt(id, 10);
  getAccountName(int, x);

}
// Go into first element of array and get AccountId value


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

I had to pass the count from my for loop into my getAccountName function. Now it works as it should. Hope this helps somebody.

Upvotes: 1

Related Questions