The important piece of info I've been missing is that by default d3 uses the index of the element as it's ID. To use a custom ID you need to pass a function to the data() method that returns that actual ID of the element:

var data = [
    {'id': 1, 'value': 3324},
    {'id': 2, 'value': 32432},
    {'id': 3, 'value': 98},
    // ...
];

var bars = svg.selectAll("rect")
    .data(data, function(d, i) {
        return d.id;
    });

By using a "custom identifier" on each record of the dataset D3 is able to track both: changes to the records attributes and changes to the position of the record inside of the data list. If the dataset is a set of unique values then a custom ID is not required, simply using the value itself will suffice:

var data = [
    3324,
    32432,
    98,
];

var bars = svg.selectAll("rect")
    .data(data, function(d) {
        return d;
    });