parola
parola

Reputation: 41

D3.nest() isn't giving me the data structure I need

I'm using D3 and having trouble getting my data nested the way I need. I'll try to simplify the scenario to its essence for this question.

I have expense data saved to variable expenses. Each object in the array represents a single purchase on a particular date at a particular brick-and-mortar store. ("StoreID" is unique; for brevity I'm omitting street address):

// original data

var expenses =

   [
     {"storeID":"4872379","storeName":"Gap","zipCode":"10032","amount":34.88,"date":"11/12/2015"},
     {"storeID":"4872379","storeName":"Gap","zipCode":"10032","amount":-34.88,"date":"11/15/2015"},
     {"storeID":"2209875","storeName":"Banana Republic","zipCode":"10003","amount":1650.54,"date":"12/01/2015"},
     {"storeID":"5434432","storeName":"Gap","zipCode":"10031","amount":120.11,"date":"11/18/2015"},
     {"storeID":"5434432","storeName":"Gap","zipCode":"10031","amount":45.5,"date":"12/01/2015"},
     {"storeID":"5434432","storeName":"Gap","zipCode":"10031","amount":117.08,"date":"12/01/2015"}
   ]

What I want to do is group amount/date pairs as objects in a single array for each unique store. This is what I'd like to end up with:

// desired structure

  [
    {"key":"2209875",
     "storeName":"BananaRepublic",
     "zipCode":"10003",
     "values": [
       {"amount":1650.54,
        "date":"12/01/2015"}]
    },
    {"key":"4872379",
     "storeName":"Gap",
     "zipCode":"10032",
     "values": [
        {"amount":34.88,
         "date":"11/12/2015"},
        {"amount":-34.88,
         "date":"11/15/2015"}]
    }, 
    {"key":"5434432",
     "storeName":"Gap",
     "zipCode":"10031",
     "values": [
       {"amount":120.11,
        "date":"11/18/2015"},
       {"amount":45.5,
        "date":"12/01/2015"},
       {"amount":117.08,
        "date":"12/01/2015"}]
    }
  ]

Using d3.nest(), I'm only able to get this far:

 // getting closer

 var expensesByStoreID = d3.nest()
   .key(function(d) { return d.storeID; })
   .entries(expenses);

 // expensesByStoreID holds this:

[
  {"key":"2209875",
   "values": [
      {"storeID":"2209875",
       "storeName":"BananaRepublic",
       "zipCode":"10003",
       "amount":1650.54,
       "date":"12/01/2015"}]
  },
  {"key":"4872379",
   "values": [
      {"storeID":"4872379",
       "storeName":"Gap",
       "zipCode":"10032",
       "amount":34.88,
       "date":"11/12/2015"},
      {"storeID":"4872379",
       "storeName":"Gap",
       "zipCode":"10032",
       "amount":-34.88,
       "date":"11/15/2015"}]
   }, 
   {"key":"5434432",
    "values": [
       {"storeID":"5434432",
        "storeName":"Gap",
        "zipCode":"10031",
        "amount":120.11,
        "date":"11/18/2015"},
       {"storeID":"5434432",
        "storeName":"Gap",
        "zipCode":"10031",
        "amount":45.5,
        "date":"12/01/2015"},
       {"storeID":"5434432",
        "storeName":"Gap",
        "zipCode":"10031",
        "amount":117.08,
        "date":"12/01/2015"}]
    }
]

Each amount and date are together in an object but the store details are also there, repeatedly. I want the store details stored just once per store object. It becomes an efficiency problem because the database contains many thousands of stores and purchases.

Is there something I can change in my d3.nest() code? Is there a plain Javascript function that would be able to turn my data structure from "original" to "desired"? Any help would be appreciated. :-)

Upvotes: 1

Views: 82

Answers (2)

parola
parola

Reputation: 41

Actually, this gives me the structure I was looking for:

var data = expensesByStoreID.map(function(d) {
    return {storeID: d.key,
            storeName: d.values[0].storeName,
            zipCode: d.values[0].zipCode,
            values: d.values.map(function(k) {
                return { amount: k.amount,
                         date: k.date
                       }
                   })
            }
        })

document.body.appendChild(document.createElement('pre')).innerHTML = JSON.stringify(data, null, 2)

[
  {
    "storeID": "2209875",
    "storeName": "Banana Republic",
    "zipCode": "10003",
    "values": [
      {
        "amount": 1650.54,
        "date": "12/01/2015"
      }
    ]
  },
  {
    "storeID": "4872379",
    "storeName": "Gap",
    "zipCode": "10032",
    "values": [
      {
        "amount": 34.88,
        "date": "11/12/2015"
      },
      {
        "amount": -34.88,
        "date": "11/15/2015"
      }
    ]
  },
  {
    "storeID": "5434432",
    "storeName": "Gap",
    "zipCode": "10031",
    "values": [
      {
        "amount": 120.11,
        "date": "11/18/2015"
      },
      {
        "amount": 45.5,
        "date": "12/01/2015"
      },
      {
        "amount": 117.08,
        "date": "12/01/2015"
      }
    ]
  }
]

Upvotes: 0

Cyril Cherian
Cyril Cherian

Reputation: 32327

You can do like this:

var expenses =

   [
     {"storeID":"4872379","storeName":"Gap","zipCode":"10032","amount":34.88,"date":"11/12/2015"},
     {"storeID":"4872379","storeName":"Gap","zipCode":"10032","amount":-34.88,"date":"11/15/2015"},
     {"storeID":"2209875","storeName":"Banana Republic","zipCode":"10003","amount":1650.54,"date":"12/01/2015"},
     {"storeID":"5434432","storeName":"Gap","zipCode":"10031","amount":120.11,"date":"11/18/2015"},
     {"storeID":"5434432","storeName":"Gap","zipCode":"10031","amount":45.5,"date":"12/01/2015"},
     {"storeID":"5434432","storeName":"Gap","zipCode":"10031","amount":117.08,"date":"12/01/2015"}
   ];

expensesByStoreID = d3.nest()
        .key(function(d) {
            return d.storeID;//group by store id
        })
        .entries(expenses);
//now designing the data output of nest into your desired format 
    var data = expensesByStoreID.map(function(d) {
        return {
            key: {
                storeID: d.key,//changing the key structure
                storeName: d.values[0].storeName,
                zipCode: d.values[0].zipCode
            },
            values: d.values.map(function(k) {
                return {
                    amount: k.amount, //changing the values structure
                    date: k.date
                }
            })
        };
    })
    console.log(data);
document.body.appendChild(document.createElement('pre')).innerHTML = JSON.stringify(data, null, 2)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Upvotes: 1

Related Questions