jQuery.data() and the data- attribute are two different stores

.data() reads a data- attribute the first time it is asked and then caches the value in jQuery’s own store, keyed off an expando property on the element. Every write after that goes to the store. The attribute in the document is never touched again, so the DOM and the value your script is reading quietly diverge.

<tr id="row-91" data-total="4900" data-active="true">

$('#row-91').data('total');        // 4900 — a Number, jQuery coerced it
$('#row-91').data('active');       // true — a Boolean, likewise

$('#row-91').data('total', 5400);

$('#row-91').data('total');        // 5400
$('#row-91').attr('data-total');   // "4900" — the document never changed

$('tr[data-total="5400"]').length; // 0

Two things follow from that and both show up as bugs somewhere else. The coercion is the first: data() converts anything that looks like a number, a boolean, or JSON into the corresponding type, so a strict comparison against a string fails and a code like data-sku="0091" arrives as the number 91. When the exact text matters, attr() is the accessor, and when the value has to survive a round trip, attr('data-total', v) is the setter — a CSS attribute selector, a server-side scrape and anything reading the markup can only see the attribute. The second is that the store lives on the element rather than in it, so clone() without true loses everything data() wrote while the data- attributes come across intact. That is the whole explanation for the classic “works on the original row, not on the duplicated one”, and it takes an hour to find if you assume the two are the same store.